策略模式(一)

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

概念是挺抽象的,没有明白策略模式是怎么回事之前,只看它的定义的话,可能没什么用。一个好的例子可以帮助我们更好地理解概念。下面的例子是从《Head First 设计模式》一书来的,通过该例子我们可以对策略模式有一个初步认识。

  • 首先,定义一个Duck类,该类是抽象的。
/**
 * 抽象的鸭子类
 */
public abstract class Duck {

    /*
     * Duck 类中的接口属性,并没有提供默认值,而是在子类中去完成默认配置,所以在使用时很可能出现空指针错误
     */

    FlyBehavior flyBehavior;

    QuackBehavior quackBehavior;

    // 不变的
    public abstract void display();

    // 不变的
    public void swim() {
        System.out.println("All ducks can swim.");
    }

    // 会变化的 - 委托给行为类 - 其实就是算法族
    public void performFly() {
        flyBehavior.fly();
    }

    // 会变化的 - 委托给行为类 - 其实就是算法族
    public void performQuack() {
        quackBehavior.quack();
    }

    public FlyBehavior getFlyBehavior() {
        return flyBehavior;
    }

    public void setFlyBehavior(FlyBehavior flyBehavior) {
        this.flyBehavior = flyBehavior;
    }

    public QuackBehavior getQuackBehavior() {
        return quackBehavior;
    }

    public void setQuackBehavior(QuackBehavior quackBehavior) {
        this.quackBehavior = quackBehavior;
    }
}

从抽象类中可以看出,对于基本不会变化的方法,我们可以在抽象类中定义甚至直接在抽象类中实现,而会变化的方法,我们只是以接口的形式在抽象类中给出。

在这里,FlyBehavior和QuackBehavior接口就代表了策略模式定义中所说的算法族,这些接口的具体实现就是一个个不同的算法,或者说一个个不同的策略。

  • 分别看一下我们定义的算法族以及算法
/**
 * 飞的行为 - 算法族
 */
public interface FlyBehavior {

    void fly();

}
/**
 * 不会飞 - 具体算法
 */
public class FlyNoWay implements FlyBehavior {

    @Override
    public void fly() {
        System.out.println("Can not fly.");
    }

}
/**
 * 用翅膀飞 - 具体算法
 */
public class FlyWithWings implements FlyBehavior {

    @Override
    public void fly() {
        System.out.println("Fly with wings.");
    }

}
/**
 * 叫的行为 - 算法族
 */
public interface QuackBehavior {

    void quack();

}
/**
 * 正常叫 - 具体算法
 */
public class NormalQuack implements QuackBehavior {

    @Override
    public void quack() {
        System.out.println("Normally quack.");
    }

}
/**
 * 小声叫 - 具体算法
 */
public class MuteQuack implements QuackBehavior {

    @Override
    public void quack() {
        System.out.println("Silently quack.");
    }

}
  • 接下来的问题就是这些具体的算法该怎样应用,如下所示:
/**
 * 野鸭
 */
public class MallardDuck extends Duck {

    /**
     * 这里做的不好 - 因为它是针对具体实现编程
     *
     * 见 Head First 设计模式 17 页
     */
    public MallardDuck() {
        /*
         * 父类中的接口属性,并没有提供默认值,而是在子类中去完成默认配置,所以在使用时很可能出现空指针错误
         */
        flyBehavior = new FlyNoWay();
        quackBehavior = new NormalQuack();
    }

    @Override
    public void display() {
        System.out.println("This is mallard.");
    }

}

可以看出,MallardDuck类是Duck的具体实现,它在自己的构造方法中引入了具体的算法(虽然这样做并不是最好的方案)。

  • 测试
/**
 * 设计模式
 */
public class DesignPatternTest {

    /**
     * 策略设计模式 - 见 Head First 设计模式 22 页
     * 
     * 策略模式定义了算法族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化独立于使用算法的客户。
     */
    @Test
    public void StrategyTest() {
        Duck duck = new MallardDuck();
        duck.display();
        duck.swim();
        duck.performFly();
        duck.performQuack();
        // 动态改变飞和叫的行为
        duck.setFlyBehavior(new FlyWithWings());
        duck.setQuackBehavior(new MuteQuack());
        duck.performFly();
        duck.performQuack();
    }

}

如果看懂了上面的例子的话,到这里,脑子中应该已经可以画出本例的类图了。

补充

  • 对于上面定义的野鸭类,我们可以做一个小的调整
/**
 * 野鸭
 */
public class MallardDuck extends Duck {

    public MallardDuck(FlyBehavior flyBehavior, QuackBehavior quackBehavior) {
        this.flyBehavior = flyBehavior;
        this.quackBehavior = quackBehavior;
    }

    @Override
    public void display() {
        System.out.println("This is mallard.");
    }

}
  • 然后像这样为野鸭指定具体飞和叫的行为
Duck duck = new MallardDuck(new FlyWithWings(), new MuteQuack());

其实,在本例中,我们可以把MallardDuck看做是策略应用的上下文,它决定了该调用哪个具体的策略。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值