開放封閉原則--OCP

 
一、OCP簡介(OCP--Open-Closed Principle):
Software entities(classes,modules,functions,etc.) should be open for extension, but closed for modification。
軟件實體應當對擴展開放,對修改關閉,即軟件實體應當在不修改(在.Net當中可能通過代理模式來達到這個目的)的前提下擴展。
Open for extension:當新需求出現的時候,可以通過擴展現有模型達到目的。   
Close for modification:對已有的二進制代碼,如dll,jar等,則不允許做任何修改。
    
二、OCP舉例:
1、例子一
假如我們要寫一個工資稅類,工資稅在不同國家有不同計算規則,如果我們不堅持OCP,直接寫一個類封裝工資稅的算稅方法,而每個國家對工資稅的具體實現細節是不盡相同的!如果我們允許修改,即把現在系統需要的所有工資稅(中國工資稅、美國工資稅等)都放在一個類裏實現,誰也不能保證未來系統不會被賣到日本,一旦出現新的工資稅,而在軟件中必須要實現這種工資稅,這個時候我們能做的只有找出這個類文件,在每個方法里加上日本稅的實現細節並重新編譯成DLL!雖然在.NET的運行環境中,我們只要將新的DLL覆蓋到原有的DLL即可,並不影響現有程序的正常運行,但每次出現新情況都要找出類文件,添加新的實現細節,這個類文件不斷擴大,以後維護起來就變的越來越困難,也並不滿足我們以前說的單一職責原則(SRP),因爲不同國家的工資稅變化都會引起對這個類的改變動機!如果我們在設計這個類的時候堅持了OCP的話,把工資稅的公共方法抽象出來做成一個接口,封閉修改,在客戶端(使用該接口的類對象)只依賴這個接口來實現對自己所需要的工資稅,以後如果系統需要增加新的工資稅,只要擴展一個具體國家的工資稅實現我們先前定義的接口,就可以正常使用,而不必重新修改原有類文件!
 
2、例子二
下面這個例子就是既不開放也不封閉的,因爲Client和Server都是具體類,如果我要Client使用不同的一個Server類那就要修改Client類中所有使用Server類的地方爲新的Server類。
class Client
{
   Server server;
   void GetMessage()
   {
      server.Message();
   }
}
 
class Server
{
   void Message();
}
 
下面爲修改後符合OCP原則的實現,我們看到Server類是從ClientInterface繼承的,不過ClientInterface卻不叫ServerInterface,原因是我們希望對Client來說ClientInterface是固定下來的,變化的只是Server。這實際上就變成了一種策略模式(Gof Strategy)
interface ClientInterface
{
    public void Message();
    //Other functions
}
 
class Server:ClientInterface
{
    public void Message();
}
 
class Client
{
   ClientInterface ci;
   public void GetMessage()
   {
       ci.Message();
   }
   public void Client(ClientInterface paramCi)
   {
       ci=paramCi;
   }
}
 
//那麼在主函數(或主控端)則
public static void Main()
{
   ClientInterface ci = new Server();
   //在上面如果有新的Server類只要替換Server()就行了.
   Client client = new Client(ci);
   client.GetMessage();
}
 
3、例子三
使用Template Method實現OCP:
public abstract class Policy
{
    private int[] i ={ 1, 1234, 1234, 1234, 132 };
    public bool Sort()
    {
        SortImp();
    }
    protected virtual bool SortImp()
    {
 
    }
}
 
class Bubbleimp : Policy
{
    protected override bool SortImp()
    {
        //冒泡排序
    }
}
class Bintreeimp : Policy
{
    protected override bool SortImp()
    {
        //二分法排序
    }
}
 
//主函數中實現
static void Main(string[] args)
{
    //如果要使用冒泡排序,只要把下面的Bintreeimp改爲Bubbleimp
    Policy sort = new Bintreeimp();
    sort.Sort();
}
 
 
三、OCP優點:
1、降低程序各部分之間的耦合性,使程序模塊互換成爲可能;
2、使軟件各部分便於單元測試,通過編制與接口一致的模擬類(Mock),可以很容易地實現軟件各部分的單元測試;
3、利於實現軟件的模塊的呼喚,軟件升級時可以只部署發生變化的部分,而不會影響其它部分;
 
四、使用OCP注意點:
1、實現OCP原則的關鍵是抽象;
2、兩種安全的實現開閉原則的設計模式是:Strategy pattern(策略模式),Template Methord(模版方法模式);
3、依據開閉原則,我們儘量不要修改類,只擴展類,但在有些情況下會出現一些比較怪異的狀況,這時可以採用幾個類進行組合來完成;
4、將可能發生變化的部分封裝成一個對象,如: 狀態, 消息,,算法,數據結構等等 , 封裝變化是實現"開閉原則"的一個重要手段,如經常發生變化的狀態值,如溫度,氣壓,顏色,積分,排名等等,可以將這些作爲獨立的屬性,如果參數之間有關係,有必要進行抽象。對於行爲,如果是基本不變的,則可以直接作爲對象的方法,否則考慮抽象或者封裝這些行爲;
5、在許多方面,OCP是面向對象設計的核心所在。遵循這個原則可帶來面向對象技術所聲稱的巨大好處(靈活性、可重用性以及可維護性)。然而,對於應用程序的每個部分都肆意地進行抽象並不是一個好主意。應該僅僅對程序中呈現出頻繁變化的那部分作出抽象。拒絕不成熟的抽象和抽象本身一樣重要;
發佈了36 篇原創文章 · 獲贊 0 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章