策略模式

我们在讲策略模式之前,先看看为什么要使用策略模式,用策略模式有什么好处

假定,我们面对着以下的需求:我们需要管理很多种类的汽车,需要用程序去描述他们

很自然的,我们会想到使用继承来复用代码,关系继承关系如下:

这里写图片描述

汽车能够跑,能够发出声音,roadster和bicycle通过继承Car,可以实现代码的复用

但是随着管理的车渐渐变多,我们发现,有的车有不同的行为方式,有不同的声音,甚至还有不同的方法,这个时候想用这种代码去管理会非常的吃力,要不断地去重写各个子类的方法,如果要增加新的方法,加在子类上不能重用代码,加在父类上,则要修正很多子类(有些子类没有此功能),这实在是太痛苦

所以我们需要把这些会改变的方法抽离出来,接下来我们来改进上面的方式

这里写图片描述
上图是我们改进后的类图,虚线代表着实现,实线代表着继承,我们把易改变的方法抽象出来,定义父接口RunBehavior与VocalBehavior,然后各种方法实例去实现这个接口

为了演示方便,我假定了一个超级汽车,可以天上飞,水中游,地上跑

下面来看代码
所有车的父类

public class Car {
    //定义跑的行为
    RunBehavior runBehavior;
    //定义发声的行为
    VocalBehavior vocalBehavior;
    //把跑的行为委托给runBehavior去完成
    public void run(){
        runBehavior.run();
    }
    //把发声的行为委托给vocalBehavior
    public void vocal(){
        vocalBehavior.vocal();
    }
}

这样做有什么好处呢?

可以让父类定义子类的方法,却不必关心子类的实现细节,降低耦合度

下面是SuperCar 和 Roadster的代码

public class SuperCar extends Car {
    //在实例化的时候定义SuperCar的行为
    public SuperCar(){
        runBehavior=new InTheSky();
        vocalBehavior=new Silence();
    }
}

public class Roadster extends Car {
    public  Roadster(){
        runBehavior=new OnTheGround();
        vocalBehavior=new Voiced();
    }
}

我们来写一个测试方法

public static void main(String[] args) {
        Car roadster=new Roadster();
        roadster.run();
        roadster.vocal();

        Car superCar=new SuperCar();
        superCar.run();
        superCar.vocal();
    }
    运行结果是:

    这是在地上跑
    这是有声的
    这是在天上飞
    这是无声的

我们来看看这样做有哪些好处?
假如,我们要重新为汽车加入一个方法,我们怎么做?

  1. 定义一个Behavior接口
  2. 写一个Behavior的实现子类
  3. 在父类加入一个Behavior属性
  4. 把具体的实现方法委托给这个Behavior去执行
  5. 在需要加入这个方法的子类里面的构造函数初始化这个Behavior

    从这个看起来,好像也没啥优势,加入一个方法需要做的事也比较多

我们来看看,假如增加一个种类的汽车?

  1. 定义一个汽车类继承Car
  2. 构造函数直间给Behavior赋值就好了,如果没有想要的功能无非就是自己写一个功能实现

我们可以看到,这种方式大大提高了代码的复用,在之前,子类中的实现是没有办法复用的

你以为这就完了?SuperCar还没有开始表演呢,怎么可能就完了
我们来改一下代码

public class Car {
    RunBehavior runBehavior;
    VocalBehavior vocalBehavior;

    public void run(){
        runBehavior.run();
    }
    public void vocal(){
        vocalBehavior.vocal();
    }
    public void setRunBehavior(RunBehavior runBehavior){
        this.runBehavior=runBehavior;
    }
}

我们在Car中加入了一个setRunBehavior的方法,用来运行时改变Car的行为
我们来测试一下看看

public static void main(String[] args) {
        Car superCar=new SuperCar();
        superCar.run();
        superCar.setRunBehavior(new InTheWater());
        superCar.run();
        superCar.setRunBehavior(new OnTheGround());
        superCar.run();
    }
    运行结果:
    这是在天上飞
    这是在水里游
    这是在地上跑

通过这种方式我们可以实现运行时改变对象的行为

回过头来,我们看一看第二种方式做了什么?

  1. 把对象的方法抽象成一个接口
  2. 对象初始化的时候才定义方法的具体实现

    我们看看原来对象和行为的关系是怎样的?
    汽车的跑是在地上跑(已经定死了)

    现在的关系呢?
    汽车有一个在地上跑的方式(可以换成别的方法)

我们把这一种行为叫做算法簇,单个的行为叫做一个算法,比方说RunBehavior,我们关注的是让汽车跑,但是他怎么跑则由你去指定算法去实现了,这就是策略模式

PS:源码地址

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值