第 25 章 策略模式
第 25 章 策略模式
1、编写鸭子项目
编写鸭子项目,具体要求如下:
- 有各种鸭子(比如野鸭、北京鸭、水鸭等, 鸭子有各种行为,比如叫、飞行等)
- 显示鸭子的信息
2、传统方案解决鸭子问题
传统方案解决方案
类图
代码实现
Duck
:鸭子的抽象父类public abstract class Duck {public Duck() {}public abstract void display();// 显示鸭子信息public void quack() {System.out.println("鸭子嘎嘎叫~~");}public void swim() {System.out.println("鸭子会游泳~~");}public void fly() {System.out.println("鸭子会飞翔~~~");}}
WildDuck
:野鸭public class WildDuck extends Duck {@Overridepublic void display() {System.out.println(" 这是野鸭 ");}}
PekingDuck
:北京烤鸭public class PekingDuck extends Duck {@Overridepublic void display() {System.out.println("~~北京鸭~~~");}// 因为北京鸭不能飞翔,因此需要重写fly@Overridepublic void fly() {System.out.println("北京鸭不能飞翔");}}
ToyDuck
;玩具鸭鸭public class ToyDuck extends Duck {@Overridepublic void display() {System.out.println("玩具鸭");}// 需要重写父类的所有方法public void quack() {System.out.println("玩具鸭不能叫~~");}public void swim() {System.out.println("玩具鸭不会游泳~~");}public void fly() {System.out.println("玩具鸭不会飞翔~~~");} }
传统的方式实现的问题分析和解决方案
- 其它鸭子,都继承了
Duck
类,所以fly
让所有子类都会飞了,这是不正确的 - 上面说的问题,其实是继承带来的问题: 对类的局部改动,尤其超类的局部改动,会影响其他部分,会有溢出效应
- 为了改进此问题,我们可以通过覆盖
fly
方法来解决 ==> 覆盖解决 - 问题又来了,如果我们有一个玩具鸭子
ToyDuck
,这样就需要ToyDuck
去覆盖Duck
的所有实现的方法 ==> 解决思路 :策略模式 (strategy pattern
)
3、策略模式基本介绍
- 策略模式(
Strategy Pattern
)中,定义算法族(策略簇),分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户 - 这算法体现了几个设计原则:
- 第一、把变化的代码从不变的代码中分离出来;
- 第二、针对接口编程而不是具体类(定义了策略接口);
- 第三、多用组合(或聚合),少用继承(客户通过组合方式使用策略)
4、策略模式的原理类图
从图中可以看到, 客户 context
有成员变量 strategy
或者其他的策略接口,至于需要使用到哪个策略, 我们可以在构造器中指定
5、策略模式解决鸭子问题
应用实例要求
编写程序完成前面的鸭子项目, 要求使用策略模式
类图
策略模式: 分别封装行为接口, 实现算法族, 超类里放行为接口对象, 在子类里具体设定行为对象。 原则就是:分离变化部分, 封装接口, 基于接口编程各种功能。 此模式让行为的变化独立于算法的使用者
代码实现
FlyBehavior
:飞行的行为(算法的提供者)public interface FlyBehavior {void fly(); // 子类具体实现 }
NoFlyBehavior
:public class NoFlyBehavior implements FlyBehavior {@Overridepublic void fly() {System.out.println(" 不会飞翔 ");}}
BadFlyBehavior
:public class BadFlyBehavior implements FlyBehavior {@Overridepublic void fly() {System.out.println(" 飞翔技术一般 ");}}
GoodFlyBehavior
:public class GoodFlyBehavior implements FlyBehavior {@Overridepublic void fly() {System.out.println(" 飞翔技术高超 ~~~");}}
QuackBehavior
:叫的行为(算法的提供者)public interface QuackBehavior {void quack();// 子类实现 }
NoQuackBehavior
:public class NoQuackBehavior implements QuackBehavior {@Overridepublic void quack() {System.out.println("不能叫");}}
GeGeQuackBehavior
:public class GeGeQuackBehavior implements QuackBehavior {@Overridepublic void quack() {System.out.println("咯咯叫");}}
GaGaQuackBehavior
:public class GaGaQuackBehavior implements QuackBehavior {@Overridepublic void quack() {System.out.println("嘎嘎叫");}}
Duck
:鸭子的抽象父类(算法的使用者),通过聚合不同的行为对象(算法的提供者),实现不同的行为模式public abstract class Duck {// 属性, 策略接口FlyBehavior flyBehavior;// 其它属性<->策略接口QuackBehavior quackBehavior;public Duck() {}public abstract void display();// 显示鸭子信息public void quack() {if (quackBehavior != null) {quackBehavior.quack();}}public void swim() {System.out.println("鸭子会游泳~~");}public void fly() {// 改进if (flyBehavior != null) {flyBehavior.fly();}}public void setFlyBehavior(FlyBehavior flyBehavior) {this.flyBehavior = flyBehavior;}public void setQuackBehavior(QuackBehavior quackBehavior) {this.quackBehavior = quackBehavior;}}
WildDuck
:public class WildDuck extends Duck {// 构造器,传入FlyBehavior 和 QuackBehavior 的对象public WildDuck() {flyBehavior = new GoodFlyBehavior();quackBehavior = new GeGeQuackBehavior();}@Overridepublic void display() {System.out.println(" 这是野鸭 ");}}
PekingDuck
:public class PekingDuck extends Duck {// 假如北京鸭可以飞翔,但是飞翔技术一般public PekingDuck() {flyBehavior = new BadFlyBehavior();quackBehavior = new GaGaQuackBehavior();}@Overridepublic void display() {System.out.println("~~北京鸭~~~");}}
ToyDuck
:public class ToyDuck extends Duck {public ToyDuck() {flyBehavior = new NoFlyBehavior();quackBehavior = new NoQuackBehavior();}@Overridepublic void display() {System.out.println("玩具鸭");}public void swim() {System.out.println("玩具鸭不会游泳~~");}}
Client
:测试代码public class Client {public static void main(String[] args) {WildDuck wildDuck = new WildDuck();wildDuck.fly();ToyDuck toyDuck = new ToyDuck();toyDuck.fly();PekingDuck pekingDuck = new PekingDuck();pekingDuck.fly();// 动态改变某个对象的行为, 北京鸭 不能飞pekingDuck.setFlyBehavior(new NoFlyBehavior());System.out.println("北京鸭的实际飞翔能力");pekingDuck.fly();}}
总结:将原来的继承方式改为组合(或聚合)方式,来实现对象的行为,可以将算法的使用者(Dick
)与算法的提供者(FlyBehavior
和 QuackBehavior
)解耦
6、JDK Arrays 源码分析
代码
public class Strategy {public static void main(String[] args) {// TODO Auto-generated method stub// 数组Integer[] data = { 9, 1, 2, 8, 4, 3 };// 实现降序排序,返回-1放左边,1放右边,0保持不变// 说明// 1. 实现了 Comparator 接口(策略接口) , 匿名类 对象 new Comparator<Integer>(){..}// 2. 对象 new Comparator<Integer>(){..} 就是实现了 策略接口 的对象// 3. public int compare(Integer o1, Integer o2){} 指定具体的处理方式Comparator<Integer> comparator = new Comparator<Integer>() {public int compare(Integer o1, Integer o2) {if (o1 > o2) {return -1;} else {return 1;}};};// 说明/** public static <T> void sort(T[] a, Comparator<? super T> c) {if (c == null) {sort(a); //默认方法} else { if (LegacyMergeSort.userRequested)legacyMergeSort(a, c); //使用策略对象celse// 使用策略对象cTimSort.sort(a, 0, a.length, c, null, 0, 0);}}*///方式1 Arrays.sort(data, comparator);System.out.println(Arrays.toString(data)); // 降序排序// 方式2- 同时lambda 表达式实现 策略模式Integer[] data2 = { 19, 11, 12, 18, 14, 13 };Arrays.sort(data2, (var1, var2) -> {if (var1.compareTo(var2) > 0) {return -1;} else {return 1;}});System.out.println("data2=" + Arrays.toString(data2));}}
总结
Comparator
为策略接口(算法的提供者),其实现对象指明了具体算法的行为,Arrays
为算法的使用者,通过组合(聚合)不同的算法提供者,实现不同的算法行为
7、策略模式的注意事项和细节
- 策略模式的关键是: 分析项目中变化部分与不变部分
- 策略模式的核心思想是:多用组合(聚合),少用继承;用行为类组合,而不是行为的继承,这样更有弹性
- 体现了“对修改关闭,对扩展开放”原则,客户端增加行为不用修改原有代码,只要添加一种策略(或者行为)即可, 避免了使用多重判断语句(
if..else if..else
) - 提供了可以替换继承关系的办法: 策略模式将算法封装在独立的
Strategy
类中使得你可以独立于其Context
改变它,使它易于切换、易于理解、易于扩展 - 需要注意的是:每添加一个策略就要增加一个类,当策略过多时,会导致类数目庞大
第 25 章 策略模式相关推荐
- 第1章 策略模式【StrategyPattern】
刘备要到江东娶老婆了,走之前诸葛亮给赵云(伴郎)三个锦囊妙计,说是按天机拆开解决棘手问题,嘿,还别说,真是解决了大问题,搞到最后是周瑜陪了夫人又折兵呀,那咱们先看看这个场景是什么样子的. 先说这个场景 ...
- 大话设计模式 第二章 策略模式购物车价格查询
策略模式定义 定义一系列功能 把它们一个个封装起来 并使它们可以相互替换 提供统一的入口访问包装的功能 问题 添加商品和优惠券到购物车后查询价格 思考 要想获取购物车的支付价格 需要经过所有的优惠券优 ...
- 【Head First 模式设计】第1章 策略模式
Intro to Design Patterns Welcome to Design Patterns SimUDuck应用程序 一个模拟鸭子游戏:SimUDuck.游戏中会出现各种鸭子,一边游泳,一 ...
- 第 1 章 策略模式
<?php header("Content-type: text/html; charset=UTF-8"); /** * 策略模式的好处就是:体现了高内聚低耦合的特性 */ ...
- 大话设计模式之爱你一万年:第十三章 行为型模式:策略模式:女友在手,说走就走:2.策略模式之出行旅游
要出行旅游,那么出行方式有--飞机.自驾游.火车.自行车等,这几种方式就是策略.我自己就不喜欢做攻略和计划,幸亏有我的女朋友. 一.策略模式之出行旅游 1.1 分析 对于出行方式可以抽象出来Vehic ...
- 大话设计模式之爱你一万年:第十三章 行为型模式:策略模式:女友在手,说走就走:3.策略模式之三国刘备江东娶夫人
这一节我们在通过一个三国之刘备江东娶夫人的例子来对策略模式有一个更深的理解. 一.策略模式之三国刘备江东娶夫人 1.1 故事背景 刘备要到江东娶老婆了,走之前诸葛亮给赵云(伴郎)三个锦囊妙计,说是按天 ...
- python打折简单程序每满_[Python设计模式] 第2章 商场收银软件——策略模式
题目 设计一个控制台程序, 模拟商场收银软件,根据客户购买商品的单价和数量,计算总价. 基础版本 price = float(input("输入商品单价:")) number = ...
- 《Head First设计模式》读书笔记 -- (第一章)策略模式
本文属贫僧不吃肉原创,欢迎转载,转载请注明来自 http://never-say-never.iteye.com/blog/851923 在开始之前,先熟悉一下OO设计的一些原则. OO设计原则之一: ...
- 大话设计模式——第二章:商场促销策略模式
文章目录 前言 一.代码1.0 1.1. 代码 2.2. 存在的问题 二.代码1.1 增加打折 2.1. 代码 2.2. 存在的问题 三.代码2.0 使用简单工厂写打折类和返利类 3.1. 代码 3. ...
最新文章
- iOS自定义转场动画
- linux环境下和网络服务相关的配置文件含义及如何配置
- 程序员被辞 12 天,前领导要求回公司解释代码,结果懵了…
- Failed to load module script: The server responded with a non-JavaScript MIME type of “text/plain“.
- web 前端绘制折线_前端每日实战:苦练 CSS 基本功——图解辅助线的原理和画法...
- php ajax ip,php / ajax REMOTE_ADDR设置为伪网络适配器的IP
- 干货 | PyTorch常用代码段整理合集
- .net 4.5 新特性 async await 一般处理程序实例
- ipad怎么清理内存垃圾
- PDA应用软件开发特点
- 联合国首席AI顾问专访:我们期望AI应该是完美的,但这永远不会
- 网络正常连接,浏览器无法打开网页的解决方法
- 滑动窗口有关的算法面试题
- 程序员必备心理学——心流
- cisco Linux SRv6 实战踩坑记录
- Spring中Bean的生命周期以及三级缓存介绍
- pcb过孔漏铜_过孔露铜改善评估报告
- Proximal Distilled Evolutionary Reinforcement Learning
- Linux /etc/fstab文件详解
- iOS开发之第三方分享微信分享、朋友圈分享,史上最新最全第三方分享微信方式实现、朋友圈方式实现
热门文章
- 中国聚合混凝土行业市场供需与战略研究报告
- 2021年中国以太网测试设备市场趋势报告、技术动态创新及2027年市场预测
- 2021年中国一次性医用传感器市场趋势报告、技术动态创新及2027年市场预测
- Android 面试 缓存,荐【经典面试题】七大缓存经典问题...
- 函数式编程中的两个棘手问题
- 抖音等多款软件涉代码抄袭,字节跳动被诉赔22.74亿元;iPhone12系统更新后性能退回3年前;Qt 6.1正式发布|极客头条...
- SQL 注入竟然把我们的系统搞挂了
- 优酷爱奇艺回应被处罚;拼多多主体公司法定代表人变更,黄峥退出董事席位;斗鱼发布开源框架Jupiter | 极客头条
- 什么是 “内存管理机制”?
- 寒武纪与华为海思分庭抗礼:中立芯片公司的成人礼