咱們都知道面向對象有六大原則,23種設計模式。它們能夠指導咱們如何寫出更加優秀的代碼。六大原則是基礎,咱們面向對象編程應該儘可能聽從這六大原則,才能寫出優秀的代碼。java
23種設計模式是前人爲咱們總結出的解決某一類問題的辦法,經過使用這些模式,咱們能夠更好的解決這一類問題。固然 23 種設計模式的設計前提也是創建在六大原則基礎之上的。編程
六大原則是面向對象的六大原則,也就是說,咱們在編寫面嚮對象語言的時候,只有遵照了這六大原則才能寫出真正的面向對象。才能擁有面向對象的思想。咱們寫的代碼符合了這六大原則,有助有提升咱們代碼的質量,寫出可擴展、可維護、可讀性好、低耦合、高內聚的代碼。設計模式
固然不符合這些原則,一樣也是能夠寫代碼的,只不過寫出的代碼質量就沒有保證了,只能說勉強算是個代碼。這比如作人同樣,人也是有原則的,符合了這些原則,那就能夠作一個堂堂正正的好人,不符合這些原則,也能活着。可是當不斷的觸犯原則,最後成了一個沒有原則的人了,那麼結果顯然可見。若是隨着程序不斷的變大,代碼不斷的沒有原則,那麼最終的結果就是你的程序沒法進行下一步維護了。markdown
總之咱們在寫代碼的時候要儘可能符合這些原則!才能寫出高質量代碼!網絡
單一職責是咱們優化代碼的第一步框架
概念:就一個類而言,應該僅有一個引發它變化的緣由函數
概念可能不太好懂,簡單來講就是一個類中應該是一組相關性很高的函數、數據的封裝。測試
下面舉例子:優化
public class Activity{
// 請求網絡加載
public void requestNet(){
String url = editText.getText();
String parmas = editText.getText();
// 判斷是否符合某個條件
if(xx){
}
// 繼續判斷
if(xxx){
}
.... 等等省略1000行
}
class Adapter{
}
// 數據類
class Data{
}
class Xxx{
}
.....
}
複製代碼
像上面的例子就是一個很好的反例表明,把全部的職責所有放到了 Activity 中,把全部的函數功能都放到了 requestNet
中。這樣勢必形成 Activity 異常的臃腫,只要一個職責發生變化就能引發 Activity 的變化。好比 Adapter 變化,要去 Activity 中修改,等等都會對 Activity 形成變化。requestNet
函數中的功能不夠純粹,裏面又包含了不少其餘的功能,也會致使一樣的問題。this
這也就是概念中提到的,就一個類而言,應該僅有一個引發它變化的緣由。
單一職責的好處很明顯,讓一個類、函數只負責某一項任務或者功能,能夠達到很好的複用效果,代碼的可讀性也會加強,可讀性好了,對應的可維護性也會增長。
固然關於職責的劃分是一個很抽象的概念,每一個人的劃分都會不一樣,單一職責的劃分界限並不老是那麼清晰,有的時候劃分的很細也會帶來不方便。這是一個靈活掌握的問題,關鍵是設計代碼的時候有沒有考慮到這種思想。
Java 世界裏最基礎的設計原則,指導咱們如何創建一個穩定的、靈活的系統。
軟件中的對象(類、模塊、函數等)應該對於擴展是開放的,可是對於修改是封閉的。
在編寫代碼的過程當中,不是一成不變的,需求的變化、升級、維護等等都須要對代碼進行修改,修改的時候就不可避免地將錯誤引入本來已經測試過的舊代碼中,破壞原有系統。所以,當軟件需求發生變化的時候,咱們應該優先考慮經過擴展的方式來實現變化,而不是經過修改已有代碼來實現。
固然實際開發中擴展和修改是同時存在的。應該儘可能少的去修改代碼,想法去擴展代碼。
《面向對象軟件構造》一書中提到這一原則---開閉原則。這一想法認爲,程序一旦開發完成,程序中的一個類的實現只應該因錯誤而被修改,新的或者改變的特性應該經過新建不一樣的類實現,新建的類能夠經過繼承的方式來重用原有類。
舉個簡單的例子:
public class Hello{
BlackPen pen = new BlackPen();
void writeHello(){
pen.write("hello world");
}
}
// Pen 類能夠寫出字
public class BlackPen{
public void write(String content){
System.out.println("content");
}
}
複製代碼
上面這個程序中咱們能夠經過 BlackPen
類寫出字,有一天需求變了要求寫出紅色的字。
public class Hello{
BlackPen pen = new BlackPen();
RedPen redPen = new RedPen();
void writeHello(String flag){
switch(flag){
"XXX":
pen.wiite("hello world");
"YYY":
redPen.write("hello world")
}
}
}
// BlackPen 類能夠寫出黑字
public class BlackPen{
public void write(String content){
System.out.println(content);
}
}
// RedPen 類能夠寫出紅字
public class RedPen{
public void write(String content){
System.out.println(content);
}
}
複製代碼
這樣寫經過 switch
來判斷要調用那一個,若是繼續添加其餘顏色的筆就繼續添加。這樣貌似不錯。可是試想 Hello 是你提供給別人的一個框架,那麼別人想要繼續添加能夠寫出黃色的 Hello Wrold ,是否是就沒有辦法了,非得讓你去修改 Hello 方法才能夠,沒有了擴展性。
如今優化成
public class Hello{
Pen pen = new BlackPen();
public void setPen(Pen pen){
this.pen = pen;
}
void writeHello(){
pen.write("hello world")
}
}
public interface Pen{
write(String content);
}
// BlackPen 類能夠寫出黑字
public class BlackPen implement Pen{
public void write(String content){
System.out.println(content);
}
}
// RedPen 類能夠寫出紅字
public class RedPen implement Pen{
public void write(String content){
System.out.println(content);
}
}
複製代碼
這樣就能夠擴展而不用修改 Hello 內的代碼了。
開閉原則,對修改關閉,對擴展開放。並非說徹底的不能修改,好比上面內容,一開始只有一個 BlackPen 的時候,你沒有想到擴展,能夠那樣寫,可是隨着業務變化,出現了不一樣的 Pen。這個時候就須要考慮 Pen 要有可擴展性。就不能重複的在 Hello
類中不斷去修改了。而是換一種思路,讓其變得具備可擴展。
可使用咱們的程序更加穩定,避免修改帶來的錯誤,增長可擴展性。當一個類中的業務不斷的發生變化需求,不斷的增長業務判斷,就須要考慮到擴展性了。
構建擴展性更好的系統
所用引用基類的地方必須能透明地使用其子類的對象。
只要父類能出現的地方,子類就能夠出現,並且替換爲子類也不會產生任何錯誤或者異常,使用者可能根本就不須要知道是父類仍是子類。
里氏替換原則就是依賴於繼承、多態這兩大特性。
其實就是將依賴變成抽象,不依賴於具體的實現。
好比:
public class Window{
public void show(View child){
child.draw();
}
}
public abstract class View{
public abstract void draw();
public void measure(int width,int height){
// 測量視圖大小
}
}
public class Button extends View{
public void draw(){
// 繪製按鈕
}
}
public class TextView extends View{
public void draw(){
// 繪製文本
}
}
複製代碼
Window 是依賴於 View 的,是一個抽象類,Window 是依賴於一個抽象,而不是具體的對象。這個時候傳入任何 View 的具體對象都是能夠的。
提升擴展性,使其不依賴具體的實現,依賴抽象。
讓項目擁有變化的能力
依賴倒置原則指代了一種特定的解耦形式,使得高層次的模塊不依賴於低層的模塊的實現細節,依賴模塊被顛倒了。
依賴倒置的關鍵點:
在 Java 語言中,抽象就是指接口或抽象類。二者都是不能直接被實例化的;細節就是實現類,實現接口或者繼承抽象類而產生的類就是細節。
高層模塊就是調用端,低層模塊就是具體的實現類。也就是調用端不要依賴具體的實現類,而是經過依賴抽象的方式。其實就是面向接口編程。
其實和上面里氏替換原則相似
下降耦合性,不依賴具體細節,依賴抽象,提升可擴展性
系統有更好的靈活性
客戶端不該該依賴它不須要的接口。另外一種定義:類間的依賴關係應該創建在最小的接口上。接口隔離原則將很是龐大、臃腫的接口拆分紅更小的和更具體的接口,這樣客戶將會只須要知道他們感興趣的方法。接口隔離原則的目的是系統解開耦合,從而容易重構、更改和從新部署。
其實就是讓一個接口儘量的小,方法少,使用戶使用起來方便。
好比:一個對象實現了多個接口,有個接口是關閉功能,那麼當這個對象想要關閉的時候,調用關閉方法就能夠了,由於它實現了多個接口,有多個方法,調用的時候就暴露了其餘接口函數。這個時候咱們僅須要它暴露關閉的接口就能夠了,隱藏其餘接口信息。
使用起來更加方便靈活
迪米特原則也稱爲最少知道原則。一個對象應該對其餘對象有最少的瞭解。通俗地講,一個類應該對須要耦合或調用的類知道得最少,類的內部如何實現與調用者或者依賴者沒有關係,調用者或者依賴者只須要知道它的須要的方法就能夠了,其餘的可一律無論。類與類之間關係越密切,耦合度越大,當一個類發生改變時,對另外一個類的影響也越大。
迪米特原則還能夠解釋爲:只與直接朋友通訊。
也就是說,應該儘量少的與別的朋友通訊,僅與最直接的朋友通訊。
兩個對象成爲朋友的方式有多種:組合、聚合、依賴等等。
下降依賴、使用簡單
這六大原則不是相互獨立的,而是互相融合,你中有我,我中有你。
單一職責告訴咱們要儘可能的分離代碼,不斷的精分代碼,不一樣的模塊實現不一樣的功能。這樣不會全部功能都融合在一塊,方便閱讀、維護代碼。
開閉原則、里氏替換原則、依賴倒置原則:本質上都是經過抽象來提升擴展性。不依賴具體的實現而依賴抽象,就會增長不少擴展性,抽象能夠有須要不一樣的實現。
接口隔離原則:和單一職責有相似,就是經過接口細分化,暴露最少的方法。要想有某個功能,只須要實現這個接口就能夠了,與其餘接口無關。
迪米特原則:儘可能依賴更少的類,儘可能對外界暴露更少的方法
實現這六大原則主要是經過面向接口編程,面向抽象編程。不依賴具體的實現。每一個類都有一個抽象(抽象類、接口)。當高層級模塊須要依賴這個類的時候,依賴它的抽象,而不是具體。這個時候就能夠靈活的改變其實現了。