【设计模式】之策略模式(Strategy)

来源:互联网 发布:windows azure 中国 编辑:程序博客网 时间:2024/04/29 23:32

主要内容大概就是学习设计模式时一些笔记和心得。

参考书籍有

《Head First Design Patterns》

《Design Patterns : Elements of Reusable Object-Oriented Software》

《Implementation Patterns》。


两本设计模式的书中对策略模式的定义都是一样的:定义一些列算法,封装每一个算法,并且让他们内部可交换。策略模式使得算法可以独立于使用者而变化。
Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.

从策略模式的定义可以看出,因为他们可以内部交换,所以这些算法肯定具有共同性,因此首先想到的就是这些实现这些算法的类继承自同一父类,当然在java中可能是实现了同一接口。这种内部可交换性如果对于使用者是透明的话,那么使用着肯定是通过调用基类的接口来向实例发送消息。


下面以《Head First Design Patterns》中介绍的例子来说明策略模式的用法。

首先需要定义参与者中的Context,本例中是class Duck,作为context一个比较重要的特性就是可以定义一个接口,让策略类访问它的内部数据,这个特性在本例中没有体现,稍后给出的《Design Patterns》中的示例代码中包含这个特性。

/** * Context class *  - is configured with a ConcreteStrategy object *  - maintains a reference to a Strategy object. *  - may define an interface that lets Strategy access its data. * @author <Head First Design Pattern> */public abstract class Duck {        // References to Strategy objects.     protected FlyBehavior flyBehavior;    protected QuackBehavior quackBehavior;    public Duck() {    }        public abstract void display();    public void performFly() {        flyBehavior.fly();    }    public void performQuack() {        quackBehavior.quack();    }        // Interfaces for changing behaviors dynamically.    public void setFlyBehavior(FlyBehavior fb) {        flyBehavior = fb;    }        public void setQuackBehaviro(QuackBehavior qb) {        quackBehavior = qb;    }        public void swim() {        System.out.println("All ducks float, even decoys!");    }}


然后是策略类,此处定义为一个接口类,Duck类可以利用此接口类中定义的共同方法去调用实例类中的算法。

public interface FlyBehavior {    public void fly();}
public interface QuackBehavior {    public void quack();}


如果是通过C++的模板类方法类实现策略模式,则不许要定义抽象接口。

接下来可以根据需要定义满足策略类接口的具体策略了。


public class FlyNoWay implements FlyBehavior {    public void fly() {        System.out.println("I can't fly");    }}

public class FlyRocketPowered implements FlyBehavior {    public void fly() {        System.out.println("I'm flying with a rocket!");    }}
public class FlyWidthWings implements FlyBehavior {    public void fly() {        System.out.println("I'm flying !!");    }}

public class MuteQuack implements QuackBehavior {    public void quack() {        System.out.println("<< Silence >>");    }}
public class Quack implements QuackBehavior {    public void quack() {        System.out.println("Quack");    }}
public class Squeak implements QuackBehavior {    public void quack() {        System.out.println("Squeak");    }}

通过定义可知,策略设计模式主要强调的是策略,即算法以及策略可以独立与客户端而动态改变。

因此为了使用设计模式以下Context的具体类并不是必须的,可以只存在一个Context。

public class MallardDuck extends Duck {    public MallardDuck() {        quackBehavior = new Quack();        flyBehavior = new FlyWidthWings();    }    public void display() {        System.out.println("I'm a real Mallard duck");    }}
public class ModelDuck extends Duck {    public ModelDuck() {        flyBehavior = new FlyNoWay();        quackBehavior = new Quack();    }    public void display() {        System.out.println("I'm a model duck");    }}
客户端类主要负责控制Strategy与Client的结合。

public class MiniDuckSimulator {    public static void main(String[] args) {        Duck mallard = new MallardDuck();        mallard.performQuack();        mallard.performFly();        Duck model = new ModelDuck();        model.performFly();        model.setFlyBehavior(new FlyRocketPowered());        model.performFly();    }}
这个例子比较形象的说明了策略模式的使用方法,但是在实际开发中策略类不可避免的要访问到client类的数据,

因此client类与strategy类之间如何以低耦合的方式交互有时候是比较重要的。

在GOF的设计模式中提供了两种思路

One approach is to have Context pass data in parameters to Strategy operations -- in other words, take the data to the strategy.

This keeps Strategy and Context decoupled. On the other hand, Context might pass data the Strategy doesn't need.

Another technique has a context pass itself as an argument, and the strategy requests data from the context explicitly.

当然最好的方式是取决与特定的算法与与之相关的数据需求。


策略模式的应用有编辑器,代码优化,金融设备等领域。