開放-封閉原則

開放-封閉原則的定義是——程序的實體對象(模塊、類、函數等)應該可以進行擴展,但不應該可以修改。

開放-封閉原則具有兩個特徵:

1.對於擴展是開放的;

2.對於修改是閉合的。

開放-封閉原則是面向對象開發中所有設計原則的核心。

當經過實踐,在面向對象編程時,如果要實現一個新的功能,添加一個新類來完成往往比修改現有的類更加方便和安全。這種思維就是所說的開放-封閉原則。

所謂的添加而不是修改,就是指對已有程序的擴展優先採用添加類或者模塊的方式來進行,而不是通過修改現有的類或者模塊,這樣做的原因是因爲軟件設計的本身所追求的目標就是封裝變化,降低耦合,而開放-封閉原則正是對這一目標的最直接體現。其他的設計原則,很多時候也是爲實現這一目標服務的。例如里氏替換實現最佳的,正確的集成層次,就可以保證不會違反開放-封閉原則。

“需求總是在變化的”、“世界上沒有一個軟件是一成不變的”,這些言論正是對軟件需求最經典的表達。從中透露出來的關鍵意思就是,對於軟件的設計者來說,應該在不需要對原有的 系統進行修改的情況下,實現更加靈活的系統擴展。

事實上,完全封閉的系統是不存在的,無論模塊怎麼實現封閉,到最後,總還是有一些無法封閉的變化,對應的思路就是:既然不能做到絕對的封閉,我們就選擇對那些變化進行封閉,那些進行隔離,然後對那些無法封閉的變化抽象出來,進行隔離,並允許擴展,儘可能的減少系統的開發,當系統變化出現時,及時作出反應。

舉個例子:

/**
  * Author:小青
  * Time:2017-8-27 
  * Function:動物類
  *
  */
public class Animal{
	public void Breath(){
		System.out.println("動物會呼吸");
	}
}
/**
  * Author:小青
  * Time:2017-8-27 
  * Function:貓
  *
  */
public class Cat extends Animal{
	public void CatchMouse(){
		System.out.println("貓抓老鼠");
	}
}

public class Client{
	public sttaic void main(String[] args){
		Cat cat = new Cat();
		cat.Breath();
		cat.CatchMouse();
	}
}
現在業務發生了變化,湯姆不僅會抓老鼠還在訓練後,學會了游泳

/**
  * Author:小青
  * Time:2017-8-27 
  * Function:湯姆貓
  *
  */
public class Tom extends Cat{
	public void Swimming(){
		System.out.println("湯姆在訓練後學會了游泳");
	}
}

public class Client{
	public sttaic void main(String[] args){
		Cat cat = new Cat();
		cat.Breath();
		cat.CatchMouse();

		Tom tom = new Tom();
		tom.Breath();
		tom.CatchMouse();
		tom.Swimming();
	}
}
上面通過添加一個新的類,完成了業務,但是客戶端的代碼也進行了少量的修改,那麼這種情況下,設計人員就應該對自己設計的模塊覺得選擇那種變化封閉,比較好的方式就是等到變化發生時立刻採取行動。

實現開放-封閉原則的核心就是面向抽象編程,而不是面向具體編程,因爲抽象相對來說是穩定的。讓類去依賴固定的抽象,所以對於修改來說就是封閉的;而通過面向對象的繼承以及多態,可以實現對抽象體的集成,通過重寫方法來改變固定行爲,從而實現新的擴展方法,對於擴展來說就是開放的。這是實施開放-封閉原則的固有思路,同時也是建立在里氏替換原則和合成/聚合複用原則上的。

接下來以銀行業務員分類,比較實現開發-封閉原則和未實現的區別:

/**
  * Author:小青
  * Time:2017-8-27 
  * Function:銀行業務員-未實現開放-封閉原則
  *
  */
public class BankWorker{
	//轉賬業務員
	public void saving(){
		system.out.println("存款");
	}
	//取款業務員
	public void drawing(){
		system.out.println("取款");
	}
	//轉賬業務員
	public void zhuanzhuang(){
		system.out.println("轉賬");
	}
	//基金的申購員
	public void jijjin(){
		system.out.println("基金申購");
	}
}

public class Client{
	public sttaic void main(String[] args){
		BankWorker bankworker = new BankWorker();
		bankworker.saving();
		bankworker.drawing();
		bankworker.zhuanzhuang();
		bankworker.jijjin();
	}
}
實現後的代碼

/**
  * Author:小青
  * Time:2017-8-27 
  * Function:銀行業務員接口
  *
  */
public interface BankWorker{
	public void operation();
}
/**
  * Author:小青
  * Time:2017-8-27 
  * Function:存款業務員
  *
  */
public class SavingBankWorker implements BankWorker{
	public void operation(){
		system.out.println("存款");
	}
}
/**
  * Author:小青
  * Time:2017-8-27 
  * Function:取款業務員
  *
  */
public class DrawingBankWorker implements BankWorker{
	public void operation(){
		system.out.println("取款");
	}
}
/**
  * Author:小青
  * Time:2017-8-27 
  * Function:轉賬業務員
  *
  */
public class ZhuanzhuangBankWorker implements BankWorker{
	public void operation(){
		system.out.println("轉賬");
	}
}
/**
  * Author:小青
  * Time:2017-8-27 
  * Function:基金申購業務員
  *
  */
public class JijingBankWorker implements BankWorker{
	public void operation(){
		system.out.println("基金申購");
	}
}



public class Client{
	public sttaic void main(String[] args){
		BankWorker bankWorker = new SavingBankWorker();
		bankWorker.operation();
		BankWorker bankWorker2 = new DrawingBankWorker();
		bankWorker2.operation();
		BankWorker bankWorker3 = new ZhuanzhuangBankWorker();
		bankWorker3.operation();
		BankWorker bankWorker4 = new JijingBankWorker();
		bankWorker4.operation();
	}
}

開放-封閉原則可以擴展已有的軟件系統提供新的行爲以滿足軟件的新需求,使變化中的軟件有一定的適應性和靈活性,對已有的軟件模塊,特別是最重要的抽象模塊不能再修改,使得軟件系統有一定的穩定性和延續性。

以上內容,整理自劉徑舟,張玉華編著的《設計模式其實很簡單》讀書筆記,歡迎轉載.



發佈了38 篇原創文章 · 獲贊 1 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章