设计模式01——策略模式

当我们使用继承不能很好的解决问题时,比如一些行为在子类不停的改变,并且让所有的子类都有这些行为是不恰当的,可以考虑把会变化的部分取并封装起来,这样就可以保证其他部分不受影响,这样做的好处是代码变化引起的不经意后果变少,而且系统也会变得更有弹性。

策略模式设计原则:针对接口编程,而不是针对实现编程

所谓针对接口编程,接口是一个概念,也是java的interface的构造,
“针对接口编程”关键就在于多态。利用多态,程序可以针对超类型编
程,执行时会根据实际状况执行到真正的行为

下面引用《设计模式》一书中的例子:

有一个鸭子实体,有飞和叫两种行为,但是不同的鸭子,对于这两个行为的具体实现是不一样,具体如下:

  • 模型鸭不会飞,也不会叫
  • 绿头鸭只会飞,不会叫
  • 黄头鸭会飞,也会发出咕咕的叫声
  • 黑头鸭会飞,也会发出吱吱的叫声

下面是具体的代码实现:

  • 1.定义个鸭子的抽象类,并赋予飞和叫两种行为,让所有类型的鸭子都可以继承它,而我们具体要做的就是针对接口–飞和叫这两个行为的接口来进行编程
/**
 * 鸭子的父类
 */
public abstract class Duck {
    QuackBehavior quackBehavior;//负责叫的行为接口
    FlyBeahavior flyBeahavior;//负责飞的行为接口

    public Duck() {
    }

    public void performFly() {
        flyBeahavior.fly();//委托给具体 行为
    }

    public void performQuack() {
        quackBehavior.quack();//鸭子对象不用亲自处理咕咕叫的行为,而是委托给quackBehavior引用的对象
    }

    public void swim() {
        //因为所有的鸭子都会游泳,所以不用单独抽象出来一种行为
        //这种设计就是策略模式,将变化的地方封装为接口
        System.out.println("所有的鸭子都会游泳,即使是模型鸭");
    }
    public void display() {

    }

}
  • 2.我们继续看一下飞行行为–FlyBeahavior
/**
 * 飞这一动作的接口
 */
public interface FlyBeahavior {
    void fly();
}

飞又有两种行为即会飞、不会飞,所以飞行行为有两个实现类会飞和不会飞

  • 2.1 会飞行为的实现
/**
 * 会飞
 */
public class FlyWIthWings implements FlyBeahavior {
    @Override
    public void fly() {
        System.out.println("我会飞");
    }
}
  • 2.2 不会飞的实现
/**
 * 不会飞
 */
public class FlyWithNone implements FlyBeahavior {
    @Override
    public void fly() {
        System.out.println("我不会飞");
    }
}

  • 3.叫声这一行为接口
/**
 * 叫这一行为的接口
 */
public interface QuackBehavior {

    void quack();
}

叫分为咕咕叫、吱吱叫、不会叫

  • 3.1 咕咕叫的行为
/**
 * 会叫
 */
public class Quack implements QuackBehavior {
    @Override
    public void quack() {
        System.out.println("我会咕咕的叫");
    }
}
  • 3.2 吱吱叫的行为
/**
 * 会吱吱叫
 */
public class Squeak implements QuackBehavior {
    @Override
    public void quack() {
        System.out.println("我会吱吱的叫");
    }
}
  • 3.3 不会叫的行为
/**
 * 不会叫
 */
public class MuteQuack implements QuackBehavior {
    @Override
    public void quack() {
        System.out.println("我不会叫");
    }
}

下面我们实现黄头鸭–会飞,也会咕咕的叫

/**
 * 黄头鸭--会飞也会咕咕的叫
 */
public class YellowDuck extends Duck {
    public YellowDuck() {//在此处实例化会飞也会叫的具体行为
        quackBehavior = new Quack();
        flyBeahavior = new FlyWIthWings();
    }

    public void display() {
        System.out.println("我是黄头鸭");
    }
}

我们测试运行一下试试:

/**
 * 运行主类
 */
public class MainClass {
    public static void main(String[] args) {
        Duck yellowDuck = new YellowDuck();
        yellowDuck.performFly();
        yellowDuck.performQuack();
    }
}

设计模式01——策略模式_第1张图片

至此我们实现了通过接口来实现变化地方的封装,但是在鸭子里建立了一堆动态功能还未用到,这样的话就太可惜了,所以我们通过设定方法来设定鸭子的具体行为,由此引出了动态设定行为

动态设定行为

  • 在Duck类中加入两个新方法
    /**动态设定**/
    public void setQuackBehavior(QuackBehavior quackBehavior) {
        this.quackBehavior = quackBehavior;
    }

    public void setFlyBeahavior(FlyBeahavior flyBeahavior) {
        this.flyBeahavior = flyBeahavior;
    }

最终Duck类如下:

/**
 * 鸭子的父类
 */
public abstract class Duck {
    QuackBehavior quackBehavior;//负责叫
    FlyBeahavior flyBeahavior;//负责飞

    public Duck() {
    }

    public void performFly() {
        flyBeahavior.fly();
    }

    public void performQuack() {
        quackBehavior.quack();//鸭子对象不用亲自处理咕咕叫的行为,而是委托给quackBehavior引用的对象
    }

    public void swim() {
        System.out.println("所有的鸭子都会游泳,即使是橡皮鸭");
    }

    public void display() {

    }
    /**动态设定**/
    public void setQuackBehavior(QuackBehavior quackBehavior) {
        this.quackBehavior = quackBehavior;
    }

    public void setFlyBeahavior(FlyBeahavior flyBeahavior) {
        this.flyBeahavior = flyBeahavior;
    }
}

  • 我们接下来 制造一个新的鸭子类型 模型鸭
/**
 * 模型鸭
 */
public class ModelDuck extends Duck {
    @Override
    public void display() {
        System.out.println("我是一只模型鸭子");
    }

    public ModelDuck() {
        flyBeahavior = new FlyWithNone();
        quackBehavior = new MuteQuack();
    }

}

此时这只鸭子还不会飞,不过我们动态的给他设置一些行为,比如我们给这个模型加一个火箭的飞行动力

/**
 * 拥有火箭般的飞行动力
 */
public class FlyRocketPowered implements FlyBeahavior {
    @Override
    public void fly() {
        System.out.println("我拥有火箭一般的飞行动力");
    }
}

我们测试一下

/**
 * 运行主类
 */
public class MainClass {
    public static void main(String[] args) {
//        Duck yellowDuck = new YellowDuck();
//        yellowDuck.display();
//        yellowDuck.performFly();
//        yellowDuck.performQuack();
        Duck model=new ModelDuck();
        model.display();
        model.performFly();
        //接下来动态的设定火箭动力
        model.setFlyBeahavior(new FlyRocketPowered());
        model.performFly();
    }
}

设计模式01——策略模式_第2张图片

通过这个运行结果我们可以看出我们如果想动态的改变鸭子的行为,只需调用set方法即可

策略模式的几个原则:

  • 1.多用组合,少用继承

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

下一篇:《设计模式02——观察者模式》

你可能感兴趣的:(设计模式,算法,设计模式,策略模式)