设计模式之 策略模式(Strategy Pattern)

本文深入探讨了策略模式在软件设计中的应用,通过鸭子模拟器的例子,详细解释了如何通过策略模式将行为抽象并封装,使得算法可以在运行时动态地替换,从而提高代码的灵活性和可维护性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

策略模式(Strategy Pattern)

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

从一个简单的应用说起。

背景

假如我们要设计一款鸭子模拟器。有绿头鸭,红头鸭,玩具鸭,橡皮鸭等。鸭子的行为有呱呱叫,游泳,飞翔等。根据简单的面向对象设计思路。我们先拿出第一版设计图。

第一版

在这里插入图片描述
第一版,我们抽象了一个鸭子超类。其他所有类型鸭子从超类继承。超类有呱呱叫(quack)和游泳(swim)方法。
好景不长,很快,我们的新需求出现了,鸭子需要飞行技能,于是我们故技重施,给鸭子超类添加fly()方法。
出现第二版:

第二版

在这里插入图片描述
此时,所有的鸭子子类都会继承fly()方法,但问题是,并不是所有但鸭子都能飞。比如橡皮鸭子就不会飞。还发现了其他潜藏的问题,橡皮鸭子也不会呱呱叫。所以橡皮鸭必须将quack()覆盖成“吱吱叫”(squeak)
当涉及“维护”时,为了“复用”(reuse)的目的而使用继承,结局并不完美
临时方案:各子类根据情况覆盖超类方法

第三版

在这里插入图片描述
此时,发现子类中,各种鸭子的差异很大,冗余的“什么都不做”代码有点多。我们试着将fly()方法和quack()方法抽象为接口,让有需要的子类去自行实现这两个接口如何?

第四版

在这里插入图片描述
你觉得这个设计如何?
虽然剥离出的两个接口Flyable和Quackable从某种程度解决了一些代码冗余的问题,但造成了新的问题:代码无法复用。每新建一个子类,都需要既继承Duck超类又实现接口。直到。。。。。。。

身骑白马—策略模式

找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。

是时候把鸭子的行为从Duck类中取出来了。
我们知道 Duck类内的fly()和quack()会随着鸭子的不同而改变。
为了要不这两个行为从Duck类中分开,我们要把它们从Duck类中取出来,建立一组新类来代表每个行为

那么如何设计实现飞行和呱呱叫的行为类呢?

针对接口编程,而不是针对实现编程

为了灵活的设计,从现在开始,鸭子的子类将使用接口(FlyBehavior与QuackBehavior)所表示的行为,实际的“实现”不会被绑死在鸭子的子类中。
如图:

“针对接口编程”真正的意思是“针对超类型(supertype)编程。

在这里插入图片描述
这样的设计,可以让飞行和呱呱叫的动作被其他对象复用,因为这些行为已经与鸭子类无关了。
而我们可以新增一些行为,不会影响到既有的行为类,也不会影响“使用”到飞行行为的鸭子类。

整合鸭子的行为

关键在于,鸭子现在会将飞行和呱呱叫的动作“委托”(delegate)别人处理,而不是使用定义在Duck类(或子类)内的呱呱叫和飞行方法。
在这里插入图片描述

代码实现

package strategy;

/**
 * @author zhangjinglong
 * @date 2019-11-05-21:57
 */

public abstract class Duck {

    FlyBehavior flyBehavior;
    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 fb){
        //可随时通过该方法修改子类鸭子的飞行行为
        flyBehavior=fb;
    }

    public void setQuackBehavior(QuackBehavior  qb){
//        可随时通过该方法修改子类鸭子的鸣叫行为
        quackBehavior=qb;
    }


}

package strategy;

public interface QuackBehavior {

    public void quack();
}

package strategy;

public interface FlyBehavior {
    public void fly();
}

package strategy;

/**
 * @author zhangjinglong
 * @date 2019-11-05-22:01
 */

public class FlyNoWay implements FlyBehavior {
    @Override
    public void fly() {

        System.out.println("I cat't fly");
    }
}

package strategy;

/**
 * @author zhangjinglong
 * @date 2019-11-05-22:21
 *
 * 建立一个利用火箭动力的飞行行为
 */

public class FlyRocketPowered implements FlyBehavior {
    @Override
    public void fly() {

        System.out.println("I'm flying with a rocket!!");
    }
}

package strategy;

/**
 * @author zhangjinglong
 * @date 2019-11-05-21:59
 */

public class FlyWithWings implements FlyBehavior {
    @Override
    public void fly() {
        System.out.println("I'm Flying!!!");
    }
}

package strategy;

/**
 * @author zhangjinglong
 * @date 2019-11-05-22:01
 */

public class Quack implements QuackBehavior {
    @Override
    public void quack() {

        System.out.println("strategy.Quack");
    }
}

package strategy;

/**
 * @author zhangjinglong
 * @date 2019-11-05-22:03
 */

public class MuteQuack implements QuackBehavior {
    @Override
    public void quack() {

        System.out.println("<< Slience  >>");
    }
}

package strategy;

/**
 * @author zhangjinglong
 * @date 2019-11-05-22:08
 */

public class MallarDuck extends Duck {

    public MallarDuck(){
        quackBehavior=new Quack();  //TODO 这里不够灵活
        flyBehavior=new FlyWithWings();//TODO  这里不够灵活
    }

    @Override
    public void display() {

        System.out.println("I'm a real Mallard duck");
    }
}

package strategy;

/**
 * @author zhangjinglong
 * @date 2019-11-05-22:18
 */

public class ModelDuck extends Duck {
    public ModelDuck(){
        flyBehavior=new FlyNoWay();//模型鸭是不会飞的
        quackBehavior=new Quack();//模型鸭会叫
    }

    @Override
    public void display() {

        System.out.println("I'm a model duck");
    }
}
package strategy;

/**
 * @author zhangjinglong
 * @date 2019-11-05-22:11
 * 
 * 测试类
 */

public class MiniDuckSimulator {
    public static void main(String[] args) {
        Duck mallard=new MallarDuck();
        mallard.performFly();
        mallard.performQuack();


        Duck model=new ModelDuck();
        model.performFly();//模型鸭默认不会飞
        model.setFlyBehavior(new FlyRocketPowered());//给模型鸭设定火箭动力的飞行行为
        model.performFly();//模型鸭 动态改变了飞行行为
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值