程式設計七大原則 一、開閉原則 針對我們設計的功能模塊對擴展開放,對修改關閉:利用面向介面(抽象)編程(多態的特性),實現對功能需求擴展的同時,不允許更改原來的代碼。提高對象的可復用性、可維護性、靈活性。 抽象的說,用抽象思維構建我們想要創建的實體對象,用具體實現去擴展實體對象的細節實現。 ...
程式設計七大原則
一、開閉原則
針對我們設計的功能模塊對擴展開放,對修改關閉:利用面向介面(抽象)編程(多態的特性),實現對功能需求擴展的同時,不允許更改原來的代碼。提高對象的可復用性、可維護性、靈活性。
抽象的說,用抽象思維構建我們想要創建的實體對象,用具體實現去擴展實體對象的細節實現。
具體的說,業務需求的功能可以去擴展,但是已經實現的功能不應該去修改。
需求:以簡單工廠模式和工廠方法模式理解開閉原則。
分析:
工廠模式是獲取一個實例對象的建造者模式,我們不關心對象如何產生,只關心結果。
簡單工廠模式是面對比較簡單的業務場景,用於獲取一個對象實例。我們需要傳入相關業務參數,讓簡單工廠對象去做相應的判斷,然後返回給我們對應的實例對象。這個工廠對象做了很多事情,他違背了單一職責原則,當我們的業務需要擴展的時候,這個工廠對象必須去修改,新增業務判斷,新增返回對應的實例對象。這就違背了開閉原則。
public class FruitsFactory { /** * @description: * @param fruitsName * @return com.lmc.gp13280.pattern.factory.fruits.IFruits * @date 2019/5/23 15:44 * @author lmc */ public IFruits product(String fruitsName){ if(null != fruitsName && fruitsName != ""){ System.out.println("客戶需求的水果是"+fruitsName); if("蘋果".equals(fruitsName)){ System.out.println("水果工廠生產了蘋果"); return new Apple(); } if("橙子".equals(fruitsName)){ System.out.println("水果工廠生產了橙子"); return new Orange(); } if("香蕉".equals(fruitsName)){ System.out.println("水果工廠生產了香蕉"); return new Banana(); } return null; }else{ return null; } } }
上面是一個水果工廠,我如果想要草莓,就必須的修改代碼去實現草莓的生產了。
工廠方法模式是抽象一個工廠介面,讓具體的工廠子類實例對象實現工廠介面。我們想要一個具體的實例對象,只需要找相應的子類工廠實現類就可以了,如果需要業務擴展,我們不需要修改原來的工廠子類,只需要新增新的工廠子類就行了。這就實現了業務擴展,但是不會修改原來的程式邏輯。遵循了開閉原則和單一職責原則。
public interface IFruitsFactory { /** * 工廠的生產方法 * @return IFruits */ IFruits product(); }
public class AppleFactory implements IFruitsFactory { @Override public IFruits product() { System.out.println("蘋果工廠只生產蘋果"); return new Apple(); } }
public class BananaFactory implements IFruitsFactory { @Override public IFruits product() { System.out.println("香蕉工廠只生產香蕉"); return new Banana(); } }
public class OrangeFactory implements IFruitsFactory { @Override public IFruits product() { System.out.println("橙子工廠只生產橙子"); return new Orange(); } }
上面的示例代碼中,我們要新增具體的水果工廠去擴展業務,只需要新增對應的工廠子類去實現水果工廠的介面就行了。
實現業務擴展,不改變原來的程式就是遵循開閉原則。
二、依賴倒置原則
spring的依賴註入相信大家都不陌生,其實依賴倒置原則是程式對象依賴其他對象的時候,應該依賴其抽象,不要依賴實現,應該依賴頂層對象,不要依賴具體的底層對象。因為程式的具體實現都是實現類去實現的,但是我們要去依賴實現類的頂層介面對象,這就是倒置,也就是依賴倒置。
依賴倒置原則的核心是運行時多態,程式在編譯時不會去實例化子類對象,在程式運行的時候虛擬機才會去選擇實例化具體的子類對象。
在程式設計中,一般介面定義好了,就不會去輕易改變。因為,在一個成熟的系統中,改變介面,就相當於把設計推翻重構了,你願意做這樣的事情?但是實現類,咱們可以進行輕微改動,或者說不改,新增一個新的實現類去代替。如果依賴其實現類,只要實現類改動,那麼程式員的災難是不是來了呢?如果依賴其頂層介面,我們其他依賴此介面的代碼都不需要去做任何改動,因為介面沒變啊,只需要改動需求具體的實現業務邏輯,或者新增業務子類實現介面。是不是可以提前下班了。
通過依賴倒置,可以減少類與類之間的耦合性,提高系統的穩定性,提高代碼的
可讀性和可維護性,並能夠降低修改程式所造成的風險。
/**
* 水果店
* @author: maocheng.liao
* @create: 2020-02-23 15:20
*/
public class FruitShop {
private IFruitsFactory fruitsFactory;
public IFruitsFactory getFruitsFactory() {
return fruitsFactory;
}
public void setFruitsFactory(IFruitsFactory fruitsFactory) {
this.fruitsFactory = fruitsFactory;
}
/**
* @description:
* @param :從水果生產基地去進貨水果
* @return com.lmc.gp13280.pattern.factory.fruits.IFruits
* @date 2020/2/23 15:34
* @author maocheng.liao
*/
public IFruits getFruits(){
IFruits fruits = fruitsFactory.product();
return fruits;
}
}
/**
* 水果店依賴倒置測試
*
* @author: maocheng.liao
* @create: 2020-02-23 15:25
*/
public class FruitShopTest {
public static void main(String[] args) {
IFruitsFactory fruitsFactory= new AppleFactory();
FruitShop fruitShop=new FruitShop();
fruitShop.setFruitsFactory(fruitsFactory);
IFruits apple = fruitShop.getFruits();
apple.getName();
fruitsFactory = new BananaFactory();
fruitShop.setFruitsFactory(fruitsFactory);
IFruits banana = fruitShop.getFruits();
banana.getName();
fruitsFactory = new OrangeFactory();
fruitShop.setFruitsFactory(fruitsFactory);
IFruits orange = fruitShop.getFruits();
orange.getName();
}
}
上面的代碼就是最簡單的依賴倒置的實現,我們依賴的是水果工廠介面和水果介面,水果店是在水果生產基地去進貨水果,至於進貨什麼水果,取決於水果生產基地生產什麼水果和水果店想進什麼水果。而不是依賴具體的水果工廠實現類和具體的水果實現類。
- 註意:上述部分簡單代碼並未呈現,詳細代碼見博客地址:https://www.cnblogs.com/programmerkaixin/p/10918844.html
三、單一職責原則
我覺得單一職責是迪米特法則的一種體現。
單一職責原則:見名知意,專人做專事,不要多管閑事。對於類、介面、方法只負責一項自己的職責。對於自己的職責程式修改之後,不會影響到其的職責程式。高內聚,低耦合的程式必須遵循單一職責,分工明確,可讀性、可維護性高。
最簡單的示例:咱們人的手腳代替不了眼睛,眼睛也代替不了手腳。
臃腫這個詞是不是能很好的體現出單一職責原則呢?代碼寫的這麼臃腫,還能不能好好玩耍啦。
四、介面隔離原則
我覺得介面隔離原則是單一職責原則的一種體現,也是迪米特法則的一種體現。
面向對象編程,萬物皆對象。
介面隔離原則:定義多個細化而明確分工的專門介面,不要去定義一個單一臃腫的介面。對於臃腫的介面,我們不好具體實現,這樣肯定會違背單一職責原則。
最簡單的示例:對於家用小汽車對象來說,往大的說,他屬於交通工具類、他屬於車類、它屬於汽車類。往小的說,它屬於家用小汽車類、私家車類。
五、迪米特法則
迪米特法則又叫最少知道原則,也有單一職責和介面隔離原則的味道。
迪米特法則:低耦合,如何做到極致呢,那就是只依賴自己真正有關係的對象。在我職責之外的對象全部拒之門外。
我覺得這個沒啥好說的,做到了單一職責,迪米特法則很好實現吧。
六、里氏替換原則
官方定義:任何基類(父類)可以出現的地方,子類一定可以出現。 里氏替換原則是繼承復用的基石,只有當衍生類可以替換掉基類,軟體單位的功能不受到影響時,基類才能真正被覆用,而衍生類也能夠在基類的基礎上增加新的行為。當一個子類的實例應該能夠替換任何其超類的實例時,它們之間才具有is-A關係。
本人理解: 里氏替換原則是為了約束繼承泛濫,就是說,在面向對象程式設計中,必須具有is-A的關係才能去使用繼承,而不能去為了實現某一業務需求,為了方便使用繼承而繼承。
前置條件:每個方法調用之前,該方法應該校驗傳入參數的正確性,只有正確才能執行該方法,否則認為調用方違反契約,不予執行。這稱為前置條件(Pre-condition
)。
後置條件:一旦通過前置條件的校驗,方法必須執行,並且必須確保執行結果符合契約,這稱之為後置條件(Post-condition
)。也就是返回值符合。
里氏替換原則約束條件:當存在繼承關係時,子類中方法的前置條件必須與超類中被覆蓋的方法的前置條件相同或者更寬鬆;而子類中方法的後置條件必須與超類中被覆蓋的方法的後置條件相同或者更為嚴格。
不要為了繼承而繼承,而是真的有繼承關係的時候才能去繼承。
七、合成復用原則
這裡結合依賴倒置原則使用合成復用原則效果更佳。
組合(has-a):類比電腦組裝,記憶體、硬碟、cpu
、顯卡 ······ 它們之間組成了電腦,但是他們之間沒有什麼關係。這就是組合關係,生命周期一致。
聚合(contanis-a
):類比員工聚合成部門。員工和部門是相互獨立的,一兩個員工離職不影響部門對象。部門解散也不影響員工對象。
合成復用原則:程式復用儘量使用組合關係、聚合關係。儘量少使用繼承關係去實現業務需求。
繼承會把所有的實現全部暴露給子類。破壞了類的封裝性,父類的改變,會影響子類。高耦合。
組合、聚合可以很好的遵循依賴倒置原則,開閉原則。成員對象的細節實現(組合、聚合對象)對於一個新的對象是隱藏的。
合成復用原則配合依賴倒置原則,很好的遵循開閉原則。達到程式高可用、高可維、高可讀。
spring為什麼這麼牛?spring為什麼依賴註入?spring為什麼是輕量級的?