策略模式 ——解決繼承帶來的苦惱

在最近的維護版本的開發中,常常碰到的一個問題:接手的項目中使用了OO的觀念,但是大量使用繼承,形成對子類的行爲約束的過緊,子類很難擴展,此時若是修改父類的話,又容易誤傷子類(由於一些子類的行爲修改,而另外一些又不須要修改)。被百般折磨後發現了策率模式,故在此記錄下。ide

爲了表示結構,使用了下面的類圖,很簡單。DuckA,DuckB,DuckC均繼承自Duck,並在Duck中實現了Swim()Quack(),因此如今的全部的鴨子都會游泳,都會叫,由於鴨子長的能夠不同,因此在子類中分別實現了Display()。spa

Duck

這個結構沒什麼問題,也很不錯,可是有一天突出需求變動了,要求鴨子們的叫聲並不相同,但其中DuckA和DuckB叫聲是相同,而且duckD不會叫;此時最容易想到一個辦法是重寫鴨子們的Quack()方法,而且DuckA和DuckB的實現是同樣的,同時在DuckD中Quack()方法作一個空實現。這樣實現雖然簡單,可是問題不少,首先,DuckA和DuckB中的Quack代碼重複的。當A,B的叫聲發生變動時,將改兩份代碼(若是鴨子數量巨大的話,重複代碼將更多);其次,若是有一天鴨子的叫聲再次發生變化,那麼你又要修改這些Qucak()方法。最後DuckD實際上不會叫,再將Quack()方法放到父類中感受也並不合適。設計

此時,咱們可能想到第二個方案是,將變化剝離出來,即將Quack()做成接口,會叫的鴨子實現該接口。這樣看似很合適,由於解決了DuckD不會叫的問題,並且更加符合OO的設計。可是這並不能解決代碼重複的問題,即DuckA,DuckB中Quack()的實現是同樣的。繼承了接口,可是依然沒法達到代碼的複用。code

此時咱們該怎麼辦呢?blog

DuackA

這個入很不專業,僅做示意吧。咱們能夠將Quack抽象成接口,而且在父類中定義一個IQuack變量,但這個變量在子類中進行賦值。這樣父類即可以操做IQuack接口。同時咱們將不一樣的叫聲分別實現出來,即QuackA,QuackB,QuackC.這樣也解決了代碼複用的問題。這樣之後即使DuckC也更換叫聲時,咱們也能夠快速進行更換。繼承

簡單寫了些代碼:接口

public interface IQuack
    {
        void MakeQuack();
    }
    public  class  QuackA :IQuack
    {
        public void MakeQuack()
        {
           //QuackA
        }
    }

 

public abstract class Duck
    {
        public IQuack MyQuack;
        protected void Swim()
        {
            
        }
        protected virtual void Display()
        {
            
        }
        public void Quack()
        {
            MyQuack.MakeQuack();
        }
    }

    class  DuckA :Duck
    {
        public DuckA()
        {
            MyQuack = new QuackA();
        }
        protected override void Display()
        {
            // DuckA
        }
    }
相關文章
相關標籤/搜索