策略模式

概念

定义了算法族,分别封装起来,让它们之间可以相互替换,此模式让算法的相互变化独立于算法的客户。

设计原则

  1. 找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起;
  2. 针对接口编程,而不是针对实现编程;
  3. 多用组合,少用继承;

要点

  • 知道OO基础,并不足以让你设计出良好的OO系统。
  • 良好的OO设计必须具备可复用、可扩充、可维护三个特性。
  • 模式可以让我们建造出具有良好OO设计质量的系统。
  • 模式被认为是历经验证的OO设计经验。
  • 模式不是代码,而是针对设计问题的通用解决方案。你可以把它应用到特定应用中。
  • 模式不是被发明,而是被发现。
  • 大多数的模式和原则,都着眼于软件变化的主题。
  • 大多数的模式都允许系统局部改变独立于其他部分。
  • 我们常把系统中会变化的部分抽出来封装。
  • 模式让开发人员之间有共享的语言,能够最大化沟通的价值。

UML图

UML图原地址

strategy.png

代码实现

先把代码贴上去,后面再慢慢解释。

Java版本

         此版本的代码只是先实现了MallardDuck和ModelDuck这两个类的鸭子,然后进行了一些测试。剩下的RubberDuck、DecoyDuck以及RedHeadDuck都没有实现,读者如果有兴趣的话,可以自己尝试实现并进行相关的测试。

FlyBehavior.java

package strategy;

/**
 * 所有飞行行为类必须实现的接口
 * @author ysrs
 *
 */
public interface FlyBehavior
{
    public void fly();
}

FlyNoWay.java

package strategy;

/**
 * 新的FlyBehavior类型,它不具有飞行能力
 * @author ysrs
 *
 */
public class FlyNoWay implements FlyBehavior 
{
    // 这是飞行行为的实现,给“不会”飞的鸭子用(包括橡皮鸭和诱饵鸭)
    @Override
    public void fly()
    {
        System.out.println("I can't fly!");
    }
}

FlyRocketPowered.java

package strategy;

/**
 * 新的FlyBehavior类型,它具有火箭般的飞行能力
 * @author ysrs
 *
 */
public class FlyRocketPowered implements FlyBehavior
{
    @Override
    public void fly()
    {
        System.out.println("I'm flying with a rocket!");
    }
}

FlyWithWings.java

package strategy;

/**
 * 新的FlyBehavior类型,它具有普通的使用翅膀的飞行能力
 * @author ysrs
 *
 */
public class FlyWithWings implements FlyBehavior
{
    // 这是飞行行为的实现,给”真会”飞的鸭子用。。。
    @Override
    public void fly()
    {
        System.out.println("I'm flying!!");
    }
}

QuackBehavior.java

package strategy;

/**
 * 所有呱呱叫行为类必须实现的接口
 * @author ysrs
 *
 */
public interface QuackBehavior
{
    public void quack();
}

Quack.java

package strategy;

/**
 * 新的QuackBehavior类型,它具呱呱叫的能力
 * @author ysrs
 *
 */
public class Quack implements QuackBehavior
{
    @Override
    public void quack()
    {
        System.out.println("Quack!");
    }
}

Squeak.java

package strategy;

/**
 * 新的QuackBehavior类型,它具有吱吱叫的能力
 * @author ysrs
 *
 */
public class Squeak implements QuackBehavior
{
    @Override
    public void quack()
    {
        System.out.println("Squeak");
    }
}

MuteQuack.java

package strategy;

/**
 * 新的QuackBehavior类型,它不具有叫的能力
 * @author ysrs
 *
 */
public class MuteQuack implements QuackBehavior
{
    @Override
    public void quack()
    {
        System.out.println("<< Silence >>");
    }
}

Duck.java

package strategy;

/**
 * Duck(鸭子)类
 * @author ysrs
 *
 */
public abstract class Duck
{
    // 为行为接口声明两个引用变量,
    // 所有鸭子子类(在同一个package中)都继承它们
    protected FlyBehavior flyBehavior;
    protected QuackBehavior quackBehavior;
    
    public Duck()
    {
        
    }
    
    public abstract void display();
    
    public void performFly()
    {
        // 委托给行为类
        flyBehavior.fly();
    }
    
    public void performQuack()
    {
        // 委托给行为类
        quackBehavior.quack();
    }
    
    public void swim()
    {
        System.out.println("All ducks float, even decoys!");
    }
    
    // 有了下面这两个函数后,以后就可以“随时”的调用这两个方法来改变鸭子的行为
    public void setFlyBehavior(FlyBehavior flyBehavior)
    {
        this.flyBehavior = flyBehavior;
    }
    public void setQuackBehavior(QuackBehavior quackBehavior)
    {
        this.quackBehavior = quackBehavior;
    }
}

MallardDuck.java

package strategy;

/**
 * MallardDuck(绿头鸭)类
 * @author ysrs
 *
 */
public class MallardDuck extends Duck
{
    // 因为MallardDuck类是继承Duck类,所以具有
    // quackBehavior和flyBehavior实例变量
    public MallardDuck()
    {
        // 绿头鸭使用Quack类处理呱呱叫,所以当performQuack()
        // 函数被调用时,叫的职责被委托给Quack对象,而我们得到
        // 了真正的呱呱叫,而不是吱吱叫或者叫不出声。
        quackBehavior = new Quack();
        // 使用FlyWithWings作为FlyBehavior类型
        flyBehavior = new FlyWithWings();
    }
    
    public void display()
    {
        System.out.println("I'm a real Mallard duck!");
    }
}

ModelDuck.java

package strategy;

/**
 * 新的鸭子类型,模型鸭
 * @author ysrs
 *
 */
public class ModelDuck extends Duck
{
    public ModelDuck()
    {
        // 一开始,我们的模型鸭是不会飞的。
        flyBehavior = new FlyNoWay();
        quackBehavior = new Quack();
    }
    
    public void display()
    {
        System.out.println("I'm a model duck!");
    }
}

MiniDuckSimulator.java

package strategy;

/**
 * 测试类,对MallardDuck和ModelDuck两个类进行测试
 * @author ysrs
 *
 */
public class MiniDuckSimulator
{
    public static void main(String[] args)
    {
        System.out.println("-----------------------------------------");
        System.out.println("Test Model MallardDuck!");
        Duck mallard = new MallardDuck();
        // 这会调用MallardDuck继承来的performQuack()方法,进而委托给该对象的QuackBehavior
        // 对象处理,也就是说调用继承来的quackBehavior引用对象的quack()方法。
        mallard.performQuack();
        // 和performQuack()方法一样
        mallard.performFly();
        
        System.out.println("\n-----------------------------------------");
        System.out.println("Test Model Duck!");
        Duck model = new ModelDuck();
        // 第一次调用performFly()函数,会被委托给FlyBehavior对象
        // (也就是FlyNoWay实例),该对象是在模型鸭构造函数中设置的。
        model.performFly();
        // 这会调用继承来的setter方法,把火箭动力飞行的行为设定到模型鸭中。
        // 那么,模型鸭就突然具有了火箭动力飞行能力!
        model.setFlyBehavior(new FlyRocketPowered());
        // 如果设置成功了,就意味着模型鸭可以动态的改变它的飞行行为。
        // 如果把行为的实现帮死在鸭子类中,可就无法做到这样了。
        model.performFly();
    }
}

输出结果:

-----------------------------------------
Test Model MallardDuck!
Quack!
I'm flying!

-----------------------------------------
Test Model Duck!
I can't fly!
I'm flying with a rocket!
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 模拟鸭子游戏的需求 SimUDuck游戏中会出现各种鸭子,一边游泳戏水,一边呱呱叫。通过标准的OO技术,设计一个超...
    一缕阳忆往昔阅读 490评论 2 0
  • 设计原则: 多用组合,少用继承。使用组合建立系统具有很大弹性,不仅可将算法族封装成类,更可以“在运行时动态改变行为...
    CloudHunter阅读 262评论 0 0
  • 鸭子超类,添加行为的错误,在超类上直接加fly的实现,木头鸭子也会飞 当设计维护时,为了复用目的而使用继承,结局并...
    落叶大人阅读 110评论 0 0
  • 平常你在什么情况下睡不好? 1、刷手机。看新闻,煲剧,逛朋友圈。一不小心刷过头,睡意全无。 2、有心事。今天的工作...
    青墨QINGMO阅读 290评论 0 3
  • 昨天晚上我丢了一个漂流瓶 然后下午去理发 我的理发师今天不在 我也没有问 反正我知道该理什么样 关于一些幽暗森林里...
    泽熙Joe阅读 222评论 0 0