在最近的維護版本的開發中,常常碰到的一個問題:接手的項目中使用了OO的觀念,但是大量使用繼承,形成對子類的行爲約束的過緊,子類很難擴展,此時若是修改父類的話,又容易誤傷子類(由於一些子類的行爲修改,而另外一些又不須要修改)。被百般折磨後發現了策率模式,故在此記錄下。ide
爲了表示結構,使用了下面的類圖,很簡單。DuckA,DuckB,DuckC均繼承自Duck,並在Duck中實現了Swim()Quack(),因此如今的全部的鴨子都會游泳,都會叫,由於鴨子長的能夠不同,因此在子類中分別實現了Display()。spa
這個結構沒什麼問題,也很不錯,可是有一天突出需求變動了,要求鴨子們的叫聲並不相同,但其中DuckA和DuckB叫聲是相同,而且duckD不會叫;此時最容易想到一個辦法是重寫鴨子們的Quack()方法,而且DuckA和DuckB的實現是同樣的,同時在DuckD中Quack()方法作一個空實現。這樣實現雖然簡單,可是問題不少,首先,DuckA和DuckB中的Quack代碼重複的。當A,B的叫聲發生變動時,將改兩份代碼(若是鴨子數量巨大的話,重複代碼將更多);其次,若是有一天鴨子的叫聲再次發生變化,那麼你又要修改這些Qucak()方法。最後DuckD實際上不會叫,再將Quack()方法放到父類中感受也並不合適。設計
此時,咱們可能想到第二個方案是,將變化剝離出來,即將Quack()做成接口,會叫的鴨子實現該接口。這樣看似很合適,由於解決了DuckD不會叫的問題,並且更加符合OO的設計。可是這並不能解決代碼重複的問題,即DuckA,DuckB中Quack()的實現是同樣的。繼承了接口,可是依然沒法達到代碼的複用。code
此時咱們該怎麼辦呢?blog
這個入很不專業,僅做示意吧。咱們能夠將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 } }