策略模式 ——解决继承带来的苦恼

在最近的维护版本的开发中,经常碰到的一个问题:接手的项目中使用了OO的观念,可是大量使用继承,造成对子类的行为约束的过紧,子类很难扩展,此时如果修改父类的话,又容易误伤子类(因为一些子类的行为修改,而另一些又不需要修改)。被百般折磨后发现了策率模式,故在此记录下。

为了表示结构,使用了下面的类图,很简单。DuckA,DuckB,DuckC均继承自Duck,并在Duck中实现了Swim()Quack(),所以现在的所有的鸭子都会游泳,都会叫,因为鸭子长的可以不一样,所以在子类中分别实现了Display()。

Duck

这个结构没什么问题,也很不错,但是有一天突出需求变更了,要求鸭子们的叫声并不相同,但其中DuckA和DuckB叫声是相同,并且duckD不会叫;此时最容易想到一个办法是重写鸭子们的Quack()方法,并且DuckA和DuckB的实现是一样的,同时在DuckD中Quack()方法做一个空实现。这样实现虽然简单,但是问题很多,首先,DuckA和DuckB中的Quack代码重复的。当A,B的叫声发生变更时,将改两份代码(如果鸭子数量巨大的话,重复代码将更多);其次,如果有一天鸭子的叫声再次发生变化,那么你又要修改这些Qucak()方法。最后DuckD实际上不会叫,再将Quack()方法放到父类中感觉也并不合适。

此时,我们可能想到第二个方案是,将变化剥离出来,即将Quack()作成接口,会叫的鸭子实现该接口。这样看似很合适,因为解决了DuckD不会叫的问题,而且更加符合OO的设计。但是这并不能解决代码重复的问题,即DuckA,DuckB中Quack()的实现是一样的。继承了接口,但是依然无法达到代码的复用。

此时我们该怎么办呢?

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
        }
    }
posted @ 2013-08-29 20:33  暴走小白  阅读(837)  评论(2编辑  收藏  举报