策略模式

  • 定义

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

先不用着急理解定义,先看下面的例子

  • 栗子

假设我们有一个Car类(代表所有的汽车),我们知道汽车都可以发动、加速、刹车等,而现在的汽车种类有非常非常多,不同的品牌,使用不同的燃料等等,于是,为了提高代码的复用性,我们可以将所有汽车都具有的共性封装到Car类中,不同类型的车有各自的类,他们的个性就在各自的类中实现即可。代码如下:

Car类

public class Car{/*** 发动*/public void start(){System.out.println("发动");}/*** 加速*/public void accele(){System.out.println("加速");}/*** 刹车*/public void brake(){System.out.println("刹车");}
}

宝马汽车类

/*** 奔驰 继承Car类*/
public class BWMCar extends Car{/*** 查看汽车品牌*/public void getBrand(){System.out.println("宝马");}/*** 补充燃料*/public void refuel(){System.out.println("加油");}
}

特斯拉汽车类

/*** 特斯拉 继承Car*/
public class TeslaCar extends Car{/*** 查看汽车品牌*/public void getBrand(){System.out.println("特斯拉");}/*** 补充燃料*/public void refuel(){System.out.println("充电");}
}

测试运行类

public class Test {public static void main(String[] args) {BWMCar bwm = new BWMCar();TeslaCar tesla = new TeslaCar();System.out.println("=======宝马=======");bwm.start();bwm.accele();bwm.brake();bwm.getBrand();bwm.refuel();System.out.println("========特斯拉========");tesla.start();tesla.accele();tesla.brake();tesla.getBrand();tesla.refuel();}
}

运行结果:

=======宝马=======
发动
加速
刹车
宝马
加油
========特斯拉========
发动
加速
刹车
特斯拉
充电

类图

对于现在来讲这样做已经可以了,但是,开发过程中从来不缺新需求的提出。假设此时比亚迪的电动车也要添加上,如果我们继续按照上卖弄继承的方式,可以得到下面比亚迪电动车类。

public class BYDCar extends Car{/*** 查看汽车品牌*/public void getBrand(){System.out.println("比亚迪");}/*** 补充燃料*/public void refuel(){System.out.println("充电");}
}

我们可以看到,BYDCar 类和TeslaCar类除了getBrand() 的方法不一样外,refuel() 方法是一模一样的,那么我们是不是可以将这个共有的方法提取出来呢?

提取到Car中显然是不可以的,因为BWMCar 同时也继承的Car类,如果将refuel()【充电】方法提取到Car中,那么所有补充燃料方式不是充电的Car的子类都需要重写refuel()方法,当子类特别多的时候,将会是非常麻烦的事情,后期如果有变动,修改起来也会令人疯狂!

这时候你可能会有这样的想法,我们可以再设计出两个子类,一个作为汽油车的父类,一个作为电动车的父类,由这两个类继承Car,得到的类图如下所示

看似这样是可以的,但是我们知道比亚迪也有传统的汽油车,那用继承该如何实现呢?每个品牌下都有很多型号的汽车,用继承全部实现可以吗?

不论是如何实现,我们从上面两次实现中都发现了继承的缺陷,显然,继承很难满足快速变化的需求,或者说继承不是最佳的实现方式!

分析上面类图可以发现,子类很多的方法都是相同的,只是具体的实现不同。是不是非常熟悉的感觉,没错,就是接口!我们接下来的解决方法就是使用接口来实现。

首先先抽离获取品牌的方法,我们知道,汽车的品牌有很多,同时每个品牌又有非常多的型号的汽车,所以品牌非常有必要抽离!

我们抽离出一个接口Brand,所有的汽车品牌都需要实现这个接口,而具体的实现都是由具体的品牌自己确定。

同理,可以抽离出燃料补充接口:

同时我们再Car类中添加这两种行为的属性,同时抽离这两种行为,并将其委托给具体的行为接口实现类去执行

完整的类图如下:

再这里使用的是组合来整合所有的行为,而不是继承,下面用代码来实现吧

Brand接口

/*** 品牌接口*/
public interface Brand {void getBrand();}

品牌实现类

/*** 宝马品牌实现类 继承品牌接口*/
public class BWM implements Brand{public void getBrand(){System.out.println("宝马");}
}
public class Tesla implements Brand{public void getBrand(){System.out.println("特斯拉");}
}
public class BYD implements Brand{public void getBrand(){System.out.println("比亚迪");}
}

补充燃料接口

/*** 补充燃料接口*/
public interface RefuelWay {void refuel();
}

补充燃料实现接口

/*** 加油补充燃料实现类*/
public class Oil implements RefuelWay{public void refuel(){System.out.println("加油");}
}
public class Electricity implements RefuelWay{public void refuel(){System.out.println("充电");}
}

Car实现类

public class Car{/*** 展示品牌行为*/private Brand brand;/*** 补充燃料方式行为*/private RefuelWay refuelWay;/*** 构造方法中设置两种行为*/public Car(Brand brand,RefuelWay refuelWay){this.brand = brand;this.refuelWay = refuelWay;}/*** 展示品牌 委托给品牌具体实现类*/public void getBrand(){brand.getBrand();}/*** 补充燃料 委托给补充燃料的具体实现类*/public void refuel(){refuelWay.refuel();}/*** 发动*/public void start(){System.out.println("发动");}/*** 加速*/public void accele(){System.out.println("加速");}/*** 刹车*/public void brake(){System.out.println("刹车");}/*** 展示方法 方便我们测试*/public void display(){this.start();this.accele();this.brake();this.getBrand();this.refuel();}
}

测试类

public class Test {public static void main(String[] args) {// 创建不同的品牌Brand bwm = new BWM();Brand tesla = new Tesla();Brand byd = new BYD();// 创建不同的燃料补充方式RefuelWay oil = new Oil();RefuelWay electricity = new Electricity();// 构造 宝马的汽油车System.out.println("------------构造 宝马的汽油车--------------");Car car1 = new Car(bwm,oil);car1.display();// 构造 宝马电动车System.out.println("------------构造 宝马电动车--------------");Car car2 = new Car(bwm, electricity);car2.display();// 构造 特斯拉电动车System.out.println("------------构造 特斯拉电动车--------------");Car car3 = new Car(tesla,electricity);car3.display();// 构造 比亚迪电动车System.out.println("------------构造 比亚迪电动车--------------");Car car4 = new Car(byd,electricity);car4.display();// 构造 比亚迪汽油车System.out.println("------------构造 比亚迪汽油车--------------");Car car5 = new Car(byd,oil);car5.display();}
}

输出:

------------构造 宝马的汽油车--------------
发动
加速
刹车
宝马
加油
------------构造 宝马电动车--------------
发动
加速
刹车
宝马
充电
------------构造 特斯拉电动车--------------
发动
加速
刹车
特斯拉
充电
------------构造 比亚迪电动车--------------
发动
加速
刹车
比亚迪
充电
------------构造 比亚迪汽油车--------------
发动
加速
刹车
比亚

对于一开始使用的继承,如果父类后期发生变化,那么对于子类的影响是非常大的,同时继承也非常的不灵活。而使用组合时,如果后期行为发生了变化,我们只需要切换这个行为的实现类即可,而Car中使用的时实现这个行为的接口,对其子类不会产生影响,如果需要添加新的行为,只需要添加一个新的行为接口,并将其委托给具体的实现类即可。

由此我们可以得出:实际开发中,我们应当多用组合,少用继承。

这里对展示品牌和补充燃料方式行为的封装就是使用的策略模式,再次阅读策略模式的定义,应当容易理解了。

个人公众号

人人都应该会的设计模式--策略模式相关推荐

  1. Python设计模式-策略模式

    Python设计模式-策略模式 代码基于3.5.2,代码如下; #coding:utf-8 #策略模式class sendInterface():def send(self,value):raise ...

  2. 关于设计模式——策略模式-Strategy Pattern

    文章目录 1 策略模式 1.1 模拟鸭子 1.2 设计原则 1.3 整合行为 1.4 模拟鸭子代码的代码 1.5 动态设定行为 1.6 重新查看整体 1.7 继承和组合 1.8 总结 1.9 优劣期间 ...

  3. [设计模式] ------ 策略模式

    策略模式 它定义了算法家族,分别封装起来,让他们直接可以互相替换,此模式让算法的变化,不会影响到使用算法的客户 其实很简单,可能很多人都用到了,只不过还不知道这就是策略模式而已. 比如定义一个接口A, ...

  4. java 策略模式 促销_java设计模式——策略模式

    一. 定义与类型 定义:针对一组算法,将每一种算法都封装到具有共同接口的独立的类中,从而是它们可以相互替换.策略模式的最大特点是使得算法可以在不影响客户端的情况下发生变化,从而改变不同的功能.当代码中 ...

  5. Springboot 使用设计模式- 策略模式

    前言 直白点,什么场景我们需要使用到设计模式- 策略模式. 在平常的springboot项目里面做CRUD,我们的习惯性基本是 一个mapper,一个service,一个serviceImpl. 但是 ...

  6. 李建忠设计模式——策略模式Strategy

    目录 1.策略模式定义 1.动机 2.模式定义 3.结构 2.实现例子 1.问题描述 2.代码实现 3.要点总结 4.参考 1.策略模式定义 1.动机 软件构建过程中,某些对象使用的算法可能多种多样, ...

  7. 设计模式-策略模式2.0

    设计模式-策略模式2.0 前面文章我们说过了传统的策略模式的实现,本文我们简单说下设计模式中的升级版的策略模式,策略模式2.0. 代码实现 talk is cheap show me the code ...

  8. 设计模式-策略模式(Strategy)-Java

    设计模式-策略模式(Strategy)-Java 目录 文章目录 1.前言 2.示例案例-电影票打折方案 3.策略模式概述 3.1.策略模式定义 3.2.策略模式结构 3.3.策略模式结构图中角色 3 ...

  9. golang设计模式——策略模式

    策略模式 目录 策略模式 分析 应用场景 代码实现 实例 代码 单元测试 总结 策略模式核心在于利用多态性,这是目前主流的面向对象语言都支持的功能. 策略模式:它定义了算法家族,分别封装起来,让它们之 ...

最新文章

  1. cocos2dx android protobuf,Quick_Cocos2d_x V3.3 Protobuf Android
  2. 从Varchar转换为 datetime
  3. C#利用Attribute实现简易AOP介绍 (转载)
  4. 【转】VS.NET2003 调试无法启动
  5. ikvm java转换成dll_利用IKVM.NET将Java jar包转换成可供C#调用的dll文件
  6. 正则表达式入门之使用元字符
  7. wpf学习笔记二 深入学习 xaml
  8. C#中为ComboBox设定value值
  9. NYOJ 7-街区最短路径问题(曼哈顿距离)
  10. 4号线地铁站点列表_7/4号线大连路地铁站:合租主卧家具齐全~
  11. 如何准备互联网产品岗面试
  12. nx零件库插件_3DSource企业自定义零件库插件
  13. Pytorch:目标检测网络-人体关键点检测
  14. 关于Qt中QMAKESPEC环境变量
  15. 计算机操作系统存在的意义,电脑操作系统的作用
  16. 解决Cortana显示空白的情况
  17. ubuntu系统强制解锁
  18. Open3D 点云投影至指定球面(Python版本)
  19. el-upload点击打开文件上传弹窗之前进行其他操作,等待操作完成后再打开文件上传弹窗
  20. Unexpected token u in JSON at position解决方法

热门文章

  1. 五大主流软件架构模式
  2. 七牛云对象存储中的内容无法获取外链和无法下载的解决方法
  3. 写一篇纪检工作的论文
  4. linux系统最小化快捷键,Linux系统最全的控制台快捷键
  5. jsp的标准动作有哪些
  6. 论开发能力提高之道-御剑飞升的实现
  7. [Bash基础] 判断字符串相等
  8. android状态栏白色,Android如何实现状态栏白底黑字效果
  9. C#-TextBox限制文本\Text输入-只能输入数字\大小写字母\计算
  10. Android ADT——快速更新API