您的位置:首页 > 其它

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

2008-06-18 12:18 477 查看
策略模式
一、模拟鸭子游戏
父类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一组类,我们可以有一个类实现“呱呱叫”,一个类实现“吱吱叫”,还有一个类实现“安静”。

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

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

我们利用接口代表每个行为,比如FlyBehavior和QuackBehavior,而行为的每个实现都将实现其中的一个接口。
这次鸭子不会负责实现fly和quack接口,反而是由我们制造一组其他类专门实现FlyBehavior和QuackBehavior,就称为“行为”类。由行为类而不是鸭子子类实现行为接口。
以前的做法是:行为来自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();
}
}

八、“有一个”可能比“是一个”更好
每个鸭子都有一个FlyBehavior和QuackBehavior,将飞行和呱呱叫行为委托给它们代为处理。
这就是组合,和“继承”不同的地方在于,鸭子的行为不是继承来的,而是和适当的行为对象“组合”来的。

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

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

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

十:OO原则
封装变化
多用组合,少用继承
针对接口编程,不针对实现编程
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: