设计模式系列之二:策略模式(Strategy Pattern)

策略模式

一、模拟鸭子游戏

父类Duck,所有的鸭子都会呱呱叫(quack),游泳(swim),有父类负责处理;每种鸭子的外观不同,所以display()方法是抽象的。

Class Duck

 {

quack(){}

swim(){}

abstract display();

}

每个鸭子子类负责实现自己的外观;

Class MallarDuck {display(){}}

Class RedHeadDuck {display(){}}

 

二、现在需要让鸭子能飞

在父类Duck中,加入了fly()方法,现在所有的鸭子子类都能飞了……

Class Duck

 {

Fly();

quack();

swim();

abstract display();

}

但是,有些不应具备飞行能力的鸭子子类也能飞行了,比如橡皮鸭RubberDuck子类,而且橡皮鸭不能呱呱叫quack,只能吱吱叫squeak,得把Duck父类的quack覆盖成squeak

 

三、继承的方法

把橡皮鸭的fly方法覆盖掉

Class RubberDuck

{

       Quack{//吱吱叫}

Display{//橡皮鸭外观}

Fly{//覆盖,什么都不做}

}

 

但是现在又来了一个诱饵鸭类DecoyDuck既不会飞,也不会叫。

Class DecoyDuck

{

       Quack{//覆盖,什么都不做}

Display{//诱饵鸭外观}

Fly{//覆盖,什么都不做}

}

 

如果每当有新的鸭子类出现,就必须被迫检查并可能需要覆盖fly()quark()方法,这会带来很大的麻烦,不便于扩展

 

四、想到利用接口

fly()从父类中取出,放进一个”Flyable接口中,只有会飞的鸭子才实现此接口。同样,设计一个”Quackable接口,会叫的鸭子类才实现此接口(诱饵鸭不会叫)。

 

就飞行来说,不同的鸭子子类,实现flyable接口,编写具体的fly()方法,那么fly()方法的代码不能复用

无论何时你需要修改某个行为,必须往下追踪并在每一个定义辞行为的子类中修改它,不小心就会造成新的错误。

 

设计原则:找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。(把会变化的部分取出来并封装起来,以便可以轻易的改动或扩充此部分,而让其他不变部分不受影响)

 

五、分开变化和不变化的部分

为了要分开变化和不变化的部分,准备建立两组类(完全远离Duck类),一个是fly相关,是个是quack相关,每一组类将实现各自的动作。比如quack一组类,我们可以有一个类实现“呱呱叫”,一个类实现“吱吱叫”,还有一个类实现“安静”。

 

希望一切有弹性,能够“指定”行为到鸭子的实例,在“运行时”动态“改变”鸭子子类的具体行为。

 

设计原则:针对接口编程,而不是针对实现编程。

 

我们利用接口代表每个行为,比如FlyBehaviorQuackBehavior,而行为的每个实现都将实现其中的一个接口。

这次鸭子不会负责实现flyquack接口,反而是由我们制造一组其他类专门实现FlyBehaviorQuackBehavior,就称为“行为”类。由行为类而不是鸭子子类实现行为接口。

以前的做法是:行为来自Duck超类的具体实现,或是继承某个接口并由子类自行实现而来。这2种做法都是依赖与“实现”,我们被实现绑死,没法方便的更改行为。

 

针对接口编程,关键在于多态。利用多态,程序可以针对超类型编程,执行时会根据实际情况执行到真正的行为,不会绑死在超类型的行为上。“针对超类型编程”可以更明确的说出“变量声明类型应该是超类型,通常是一个抽象类或者是一个接口,如此,只要是具体实现此超类型的类所产生的对象,都可以指定给这个变量。这意味着,声明类时不用理会以后执行时的真正对象类型!”  

 

 

六、类图

飞行类

IFlyBehavior接口:所有飞行类都实现它,所有新的飞行类都必须实现fly方法。

FlyNoWay:实现所有不会飞的鸭子的动作。

FlyWithWings:实现所有用翅膀飞行的鸭子的动作。

FlyRocketPowerd:实现火箭动力飞行的鸭子的动作(玩具鸭的飞行)。

 

呱呱叫的类  

 

鸭子类

 

七、源码

IFlyBehavior.cs

public interface IFlyBehavior //所有飞行行为类必须实现的接口

{

    void fly();

}

 

FlyNoWay.cs

public class FlyNoWay:IFlyBehavior

    {

        public void fly()

        {

            System.Console.WriteLine("No Fly!");

        }

}

 

FlyWithWings.cs

public class FlyWithWings : IFlyBehavior

    {

        public void fly()

        {

            System.Console.WriteLine("Flying with Wings!");

        }

}

 

FlyRocketPowered.cs

class FlyRocketPowered:IFlyBehavior

    {

        public void fly()

        {

            System.Console.WriteLine("Flying with a Rocket!");

        }

}

 

//================

IQuackBehavior.cs

public interface IQuackBehavior

    {

        void quack();

}

 

Quack.cs

public class Quack : IQuackBehavior

    {

        public void quack()

        {

            System.Console.WriteLine("Quack!");

        }

}

 

MuteQuack.cs

class MuteQuack:IQuackBehavior

    {

        public void quack()

        {

            System.Console.WriteLine("<Silence>");

        }

}

 

Squeak.cs

class Squeak:IQuackBehavior

    {

        public void quack()

        {

            System.Console.WriteLine("Squeak!");

        }

}

 

AbstractDuck.cs

public abstract class AbstractDuck

    { 

        protected IFlyBehavior flyBehavior;

        protected IQuackBehavior quackBehavior;

 

        public IQuackBehavior QuackBehavior

        {

            get

            {

                return quackBehavior;

            }

            set

            {

                quackBehavior = value;

            }

        }

 

        public IFlyBehavior FlyBehavior

        {

            get

            {

                return flyBehavior;

            }

            set

            {

                flyBehavior = value;

            }

        }

       

        public AbstractDuck(){ }

 

        public abstract void display();

 

        public void performFly()

        {

            flyBehavior.fly();

        }

 

        public void performQuack()

        {

            quackBehavior.quack();

        }

 

        public void setFlyBehavior(IFlyBehavior fb)

        {

            flyBehavior = fb;

        }

 

        public void setQuckBehavior(IQuackBehavior qb)

        {

            quackBehavior = qb;

        }

 

        public void swim()

        {

            System.Console.WriteLine("All ducks float, even decoys!");

        }

}

 

 

MallarDuck.cs

public class MallarDuck:AbstractDuck

    {

        public MallarDuck()

        {

            QuackBehavior = new Quack();

            FlyBehavior = new FlyWithWings();

        }

        public override void display()

        {

            System.Console.WriteLine("Mallard Duck!");

        }

}

 

ModelDuck.cs

class ModelDuck:AbstractDuck

    {

        public ModelDuck()

        {

            FlyBehavior = new FlyNoWay();

            QuackBehavior = new Quack();

        }

 

        public override void display()

        {

            System.Console.WriteLine("Model Duck!");

        }

}

 

 

Program.cs

class Program

    {

        static void Main (string[] args)

        {

            AbstractDuck mallarDuck = new MallarDuck();

            mallarDuck.display();           

            mallarDuck.performFly();

            mallarDuck.performQuack();

            mallarDuck.swim();

 

            System.Console.WriteLine("-----------");

 

            AbstractDuck modelDuck = new ModelDuck();

            modelDuck.performFly();

            modelDuck.setFlyBehavior(new FlyRocketPowered());

            modelDuck.performFly();

        }

}

 

八、“有一个”可能比“是一个”更好

每个鸭子都有一个FlyBehaviorQuackBehavior,将飞行和呱呱叫行为委托给它们代为处理。

这就是组合,和“继承”不同的地方在于,鸭子的行为不是继承来的,而是和适当的行为对象“组合”来的。

 

设计原则:多用组合,少用继承

 

使用组合建立系统具有很大的弹性,不仅可以激昂算法族封装成类,更可以“在运行时动态改变行为”,只要组合的行为对象符合正确的接口标准即可。

 

九:策略模式定义

策略模式定义了算法簇,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立与使用算法的客户。

 

href="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_filelist.xml" rel="File-List" />

十:OO原则

封装变化

多用组合,少用继承

针对接口编程,不针对实现编程

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值