
溫馨提示:閱讀本文需要4-5分鐘(少量代碼)
今天,我們來解決一個問題:
如何寫出優(yōu)秀的代碼?設(shè)計模式六大原則告訴你
人生一切難題,知識給你答案。
==單一原則==
定義:應(yīng)該有且僅有一個原因引起類的變更。
單一原則適用于接口、類以及方法,對于接口,我們在設(shè)計的時候一定要做到單一,但對于實現(xiàn)類就需要多方面考慮。生搬硬套單一原則會引起類的劇增,給維護帶來非常多的麻煩。而且過分細分類的職責(zé)也會人為地增加系統(tǒng)的復(fù)雜性。
最常見的就是Activity類,如果我們在Activity中進行網(wǎng)絡(luò)請求操作,請求完畢又進行業(yè)務(wù)處理,處理之后通知View的刷新,這樣做的話Activity就會變的十分臃腫,Activity的職責(zé)就是顯示視圖并處理與用戶的交互,如何解決呢?抽離網(wǎng)絡(luò)請求操作與業(yè)務(wù)操作,通過接口回調(diào)通知Activity視圖的變更,推薦使用MVP模式。
對于單一原則,建議是接口一定要做的單一職責(zé),類的設(shè)計盡量做到只有一個原因引起變化。
==開閉原則==
定義:一個軟件實體如類、模塊和函數(shù)應(yīng)該對擴展開放,對修改關(guān)閉。
開閉原則的定義已經(jīng)非常明確地告訴我們:軟件實體應(yīng)該對擴展開放,對修改關(guān)閉,其含義是說一個軟件實體應(yīng)該通過擴展來實現(xiàn)變化,而不是通過修改已有的代碼來實現(xiàn)變化。
比如現(xiàn)有一個類ProductFactory用來生產(chǎn)一堆產(chǎn)品:
public class ProductFactory {
private final static List<Product> productList=new ArrayList<>();
static {
Product product=new Product();
product.setPrice(10);
product.setName("產(chǎn)品A");
productList.add(product);
product=new Product();
product.setPrice(10);
product.setName("產(chǎn)品B");
productList.add(product);
}
public List<Product> getProduct(){
return productList;
}
}
客戶端通過創(chuàng)建ProductFactory并調(diào)用getProduct方法就可以獲取產(chǎn)品列表,看似非常完美,如果這個時候產(chǎn)品說我想獲取產(chǎn)品A,然后過了幾天由于產(chǎn)品效益不是很高,需要做打折處理,這個時候怎么辦?是在ProductFactory類中新增方法還是直接在該方法中修改?由于業(yè)務(wù)的不斷變化,造成該類被頻繁修改。
使用開閉原則來解決,創(chuàng)建一個接口IProduct,內(nèi)部約定一個規(guī)則:
public interface IProduct {
List<Product> getProduct();
}
正常產(chǎn)品獲?。?/p>
public class ProductFactory implements IProduct {
private final static List<Product> productList=new ArrayList<>();
static {
Product product=new Product();
product.setPrice(10);
product.setName("產(chǎn)品A");
productList.add(product);
product=new Product();
product.setPrice(10);
product.setName("產(chǎn)品B");
productList.add(product);
}
@Override
public List<Product> getProduct() {
return productList;
}
}
客戶端使用:
public class Client {
public static void main(String[] args){
IProduct productFactory=new ProductFactory();
List<Product> productList=productFactory.getProduct();
}
}
產(chǎn)品經(jīng)理說我只需要產(chǎn)品A的產(chǎn)品,通過擴展來實現(xiàn):
public class ProductAFactory implements IProduct {
private final static List<Product> productList=new ArrayList<>();
static {
Product product=new Product();
product.setPrice(10);
product.setName("產(chǎn)品A");
productList.add(product);
product=new Product();
product.setPrice(10);
product.setName("產(chǎn)品B");
productList.add(product);
}
@Override
public List<Product> getProduct() {
List<Product> list=new ArrayList<>();
for(Product product:productList){
boolean isProductA=product.getName().equals("產(chǎn)品A");
if(isProductA){
list.add(product);
}
}
return list;
}
}
客戶端那邊只需要把ProductFactory替換成ProductAFactory即可,即使產(chǎn)品說需要將產(chǎn)品進行打折處理,我們只需要創(chuàng)建打折類實現(xiàn)IProduct并實現(xiàn)getProduct方法進行打折處理。
==里氏替換原則==
定義:所有引用基類(父類)的地方必須能透明地使用其子類的對象。
里氏替換原則告訴我們,在軟件中將一個基類替換成其子類對象,程序?qū)⒉粫a(chǎn)生任何錯誤和異常;反之則不行,如果一個軟件實體使用的是一個子類對象的話,那么它不一定能夠使用基類對象。
子類的所有方法必須在父類中聲明,或子類必須實現(xiàn)父類中聲明的方法。根據(jù)里氏替換原則,為了保證系統(tǒng)的擴展性,在程序中通常使用父類來進行定義。
在運用里氏替換原則時,盡量把父類設(shè)計為抽象類或者接口,讓子類繼承父類或?qū)崿F(xiàn)父接口,并實現(xiàn)在父類中聲明的方法。運行時,子類實例替換父類實例,我們可以方便地擴展系統(tǒng)的功能。
==依賴倒置原則==
定義:高層模塊不應(yīng)該依賴低層模塊,兩者都應(yīng)該依賴于抽象。抽象不應(yīng)該依賴于細節(jié),細節(jié)應(yīng)該依賴于抽象。
在Java中,抽象指接口或者抽象類,兩者都不能直接被實例化。
細節(jié)就是實現(xiàn)類,實現(xiàn)接口或繼承抽象類而產(chǎn)生的就是細節(jié)。
高層模塊就是調(diào)用端,低層模塊就是具體實現(xiàn)類。
依賴倒置的具體表現(xiàn)就是,模塊間的依賴通過抽象發(fā)生,實現(xiàn)類之間不發(fā)生直接依賴關(guān)系,其依賴關(guān)系是通過接口或者抽象類產(chǎn)生的。
如果類與類直接依賴細節(jié),那么就會直接耦合,如此一來當(dāng)修改時,就會同時修改依賴者代碼,限制了可擴展性。
==迪米特原則==
定義:一個軟件實體應(yīng)當(dāng)盡可能少地與其他實體發(fā)生相互作用。
迪米特原則又被稱為最少知識原則,通俗地講,設(shè)計系統(tǒng)時盡量減少對象之間的交互,如果兩個對象之間不必彼此直接通信,那么這兩個對象就不應(yīng)當(dāng)發(fā)生任何直接的相互作用。
如果其中的一個對象需要調(diào)用另一個對象的某個方法,可以通過第三方轉(zhuǎn)發(fā)這個調(diào)用。引入一個合理的第三者來降低現(xiàn)有對象之間的耦合度。
==接口隔離原則==
定義:一個類對另一個類的依賴應(yīng)該建立在最小的接口上。
建立單一接口,不要建立龐大臃腫的接口;盡量細化接口,接口中的方法盡量少。也就是說,我們要為各個類建立專用的接口,而不要試圖建立一個很龐大的接口供所有依賴它的類調(diào)用。
接口盡量小,但要有限度。對接口進行細化可以提高程序設(shè)計的靈活性,但是如果過度的細化,則會造成接口數(shù)量過多,使設(shè)計復(fù)雜化。