最容易被人忽視的面向物件的六大原則
作為文集的第一篇,我覺得有必要介紹一下大概的寫作規劃。整個文集將分為三個部分,分別是面向物件六大原則、23種設計模式,以及MVC、MVP、MVVM三種應用架構的介紹和使用。
如果大家看過何紅輝和關愛民老師著的《Android原始碼設計模式解析與實戰》,就會覺得似曾相識。其實,我寫這個文集的目的,就是為了鞏固我看這本書後的感悟,讓我能加深對內容的理解。
像我們平時工作,通常都是先實現所給的功能,等到修改或者擴充套件時,發現不方便,再結合問題重構模組。其實有些是可以避免的,面向物件六大原則在類這個層次上告訴我們,如何構造類、如何維護類之間的關係;23種設計模式在功能的層次上指導我們寫出精煉完善的程式碼;而應用架構的變遷反映了App層次上應用功能、資源的增加,導致維護成本的提高,急需細化模組。
1、現實中的場景
有一個工廠想生產一款產品,按照流程得先產生設計稿,然後根據設計稿做出產品原型,最後生產出產品。
2、程式碼描述現象
新建一個專案,用Factory代表工廠,通過productA方法顯示生產產品A的流程,最後在程式入口Main中呼叫。
public class Factory { public Factory() { super(); } public void productA() { System.out.println("產生設計稿A"); System.out.println("做出產品原型A"); System.out.println("生產出產品A"); } }
public class Main { public static void main(String[] args) { new Factory().productA(); } }
3、單一職責原則
定義:一個類,應該僅有一個引起它變化的原因。
目的:讓一個類專注於自身的功能。
例項:我們來看看上面的案例,明顯可以發現工廠的功能過於複雜,又是設計又是做原型又是生產,隨著業務的增加會越來越臃腫,不方便管理,所以應該將設計和原型交給專業的第三方來做。根據這個原則,可以將程式碼做如下修改:
public class DesignerA { public DesignerA() { super(); } public void design() { System.out.println("產生設計稿A"); } }
public class CompanyA { public CompanyA() { super(); } public void make() { System.out.println("做出產品原型A"); } }
public class Factory { private DesignerA mDesigner; private CompanyA mCompany; public Factory() { super(); mDesigner = new DesignerA(); mCompany = new CompanyA(); } public void productA() { mDesigner.design(); mCompany.make(); System.out.println("生產出產品A"); } }
總結:Factory的程式碼減少了,功能更明確了。當設計團隊和原型公司內部發生變化時,不會影響工廠的生產流程。
4、開閉原則(由里氏替換原則、依賴倒置原則實現)
定義:類、模組、函式等應該對於擴充套件是開放的,對於修改是封閉的。
目的:在軟體擴充套件的過程中,確保原有功能的正確性。
例項:上面的案例,已經細分了生產責任。我們就工廠來看,如果接到了公司B的產品原型咋辦,現在而言是生產不了的,沒那功能呀。所以得增加功能:
public class Factory { // 一些相關的初始化工作 public void productA() { mDesigner.design(); mCompany.make(); System.out.println("生產出產品A"); } public void productB() { // 關於產品B的設計、原型和生產 } }
可是,隨著工廠的發展,功能會不斷增加,總不能每次都整改工廠吧。所以,我們可以通過父類(里氏替換原則)或者介面(依賴倒置原則)來確定生產規範,符合的產品,工廠就能生產。下面用里氏替換原則做個示範:
// 宣告設計的規範 public abstract class Designer { public Designer() { super(); // 此處是子類不需要的 System.out.println("開始進行產品設計"); } public abstract void design(); }
// 宣告原型的規範 public abstract class Company { public Company() { super(); // 此處是子類不需要的 System.out.println("根據設計做原型"); } public abstract void make(); }
// 符合規範的設計師A public class DesignerA extends Designer { public DesignerA() { super(); } @Override public void design() { System.out.println("產生設計稿A"); } }
// 符合規範的產品公司A public class CompanyA extends Company { public CompanyA() { super(); } @Override public void make() { System.out.println("做出產品原型A"); } }
public class Factory { private Designer mDesigner; private Company mCompany; // 工廠根據不同的設計和原型生產 public Factory(Designer designer, Company company) { super(); mDesigner = designer; mCompany = company; } public void product() { mDesigner.design(); mCompany.make(); System.out.println("生產出所需的產品"); } }
public class Main { public static void main(String[] args) { // 拿到設計圖和產品原型,開始生產 new Factory(new DesignerA(), new CompanyA()).product(); } }
區別:繼承父類和實現介面的區別就是里氏替換和依賴倒置的區別。繼承可以擁有父類的所有屬性和方法,減少建立類的成本,但同時會造成系統耦合,子類程式碼冗餘,靈活性降低。介面正好相反,與之互補。
總結:開閉原則在工作中一定要實現,至於是用里氏替換還是依賴倒置,就根據當時的需求分析。
5、介面隔離原則
定義:類所依賴的介面應該僅僅包含所需要的功能。
目的:使介面的功能更加具體,類似單一職責,不過這是用於介面,使呼叫者只關注自己所需的功能。
例項:就拿宣告設計規範的Designer來說,根據依賴倒置原則,將其改為介面,為了比較說明,添加了作為人所具有的吃飯的能力:
public interface Designer { // 此處宣告設計師具有吃飯的能力 // 與為工廠設計圖紙不相關,理應去掉 void eat(); void design(); }
總結:隱藏非相關功能,除了不暴露更多細節,增加使用者學習成本,更能降低系統耦合性,提高應用靈活性。
6、迪米特原則
定義:一個類應該僅僅依賴於自己需要呼叫的物件。
目的:保證邏輯結構的清晰,降低系統的耦合程度。
例項:就拿負責生產的Factory來說,它同時含有Designer和Company。也就是隻負責生產的工廠卻要自己準備設計圖紙和產品原型,這不符合現實情況,它應該只生產所有公司交給它的規範的產品:
public abstract class Company { // 由公司和設計師打交道 private Designer mDesigner; public Company(Designer designer) { super(); designer.design(); System.out.println("根據設計做原型"); } public abstract void make(); }
public class Factory { // 工廠只和公司拿來的原型打交道 private Company mCompany; public Factory(Company company) { super(); mCompany = company; } public void product() { mCompany.make(); System.out.println("生產出所需的產品"); } }
public class Main { public static void main(String[] args) { // 生產之前確定使用哪個公司的哪個設計師作品 new Factory(new CompanyA(new DesignerA())).product(); } }
總結:通過對結果進行比較,發現修改後(右)的流程比修改前(左)的流程更加符合現實生產環境。
寫在最後:歡迎留言討論,加關注,持續更新!