从“策略模式”聊聊“设计模式”有多重要?
ID:嵌入式Hacker
作者: 可爱的东东
对于技术领域的知识点,我个人喜欢简单地划分为2类:
1.基础类2.工具类
我判断一个知识点属于哪一类的主要依据有2点:
1.这个知识点是否经久不衰;2.这个知识点是否没有替代品;
如果上述2点都满足,则我会认为这是基础类知识,属于可以长期投资的价值股; 典型的例如操作系统、数据结构、Linux环境编程、软件模式(设计模式、架构模式...)等我会归类为基础类知识;
而例如 Qt、Git、Docker、甚至各种编程语言(C、C++、Java、Python)等知识点我都会暂时归类为工具类。不要误会,这些都只是我个人的喜好,并没有要贬低你心爱的技术的意思,只要是你在工作里需要重度使用的技术,你都应该把它归类为基础类,以便提醒自己需要深耕该技术。
说了这么多,无非是想告诉你,我认为设计模式很重要,仅此而已。即便你从事的是底层软件相关的工作,你只用 C 语言进行开发,情况也是一样的。
下面是正文(策略模式入门)
需求:
模拟现实生活中的鸭子,鸭子会游泳,鸣叫,飞。
1. 利用继承?
阶段1
一个父类 Duck 定义 鸭子 的一些特性,子类继承它的特性,并覆盖(override) 父类的部分特性。至此没什么问题,子类共同拥有父类的特性,消除了代码的重复性。
新的需求:
一些鸭子(例如野鸭)是会飞的,我们要让 Duck 具有 fly() 的特性。
阶段2
在 Duck 类中加上 fly() 方法:
引入新的问题:
在父类 Duck 类中增加 fly() 后,导致所有的子类鸭子都会 fly 了。
而真实的情况是:橡皮鸭子 RubberDuck 不应该会 fly。
思考:
1.对代码的局部修改,影响层面不只是局部;
2.继承虽然能复用代码,但是它并不完美;
阶段3
在 RubberDuck 中 override fly() 方法,方法内什么都不做。
利用继承来提供Duck的行为的做法,存在什么缺点?
1.大量的代码在多个 Duck 子类中冗余,例如 RubberDuck 的 fly();
2.父类Duck的改动会牵连所有子类Duck也要跟着改动
2. 使用接口效果如何?
阶段4
让部分而非全部鸭子可飞或者可叫。
把 fly() 从父类中提取出来定义为 Flyable 接口,只有会飞的鸭子才实现此接口 。quack() 也类似地定义为 Quackable 接口。
例如橡皮鸭 RubberDuck 不会飞,所有它不实现 Flyable 接口。
思考:
1.这样避免了 “阶段3” 中类似 RubberDuck->fly() 的冗余代码,但是又造成了 fly() 毫无复用性的问题( Java 接口内不能有代码实现);
2.设计原则:把会变化的部分独立出来,不要和不需要变化的代码混在一起(Identify the aspects of your application that vary and separate them from what stays the same.);
3.各种设计模式都有一样的目的:把会变化的部分取出并封装起来,以便以后轻易的改动和扩展此部分,而不影响不需要变化的其他部分;
4.软件开发的不变真理: 软件总是要变化的;
3. 划分变化与不变的部分
总结前面的做法:
1.阶段2: 行为 ( fly 和 quake ) 来自于 Duck 类内具体实现 ( concrete implementation );
2.阶段4: 行为来自于继承某个接口的子类内的专属实现 ( specialized implementation );
3.无论是阶段2还是阶段4,都是针对具体实现编程。即每一种会飞的鸭子,都必须要有自己专属的关于 fly 的具体实现(例如 MallarDuck->fly() / RedheadDuck->fly()),而无法共用同一类 fly 的方式(例如FlyWithWings / FlyWithRocket / FlyNoWay);
提取出变化的部分:
将会变化的鸭子的行为 ( 包括fly行为和quake行为 ) 从 Duck 类中提取出来。
4. 设计鸭子的行为
阶段5
让鸭子的行为可以动态改变:
用接口代表 ( represent ) 行为,定义2个接口:FlyBehavior and QuackBehavior。
行为的每一个具体实现(implementation)都会实现(implement) 对应的接口:
前人的经验:
1.设计原则:要针对接口编程,不要针对具体实现(implementation)编程 / Program to an interface, not an implementation;
2.这里的接口是一个“抽象概念”,并不是专门指Java 里的interface;
3.针对接口编程的另一个说法是针对超类型(supertype)编程,超类型在编程语法上一般是一个抽象类(abstract class)或者接口(interface);
实现鸭子的行为:
这样做有什么好处?
1.多个行为之间相互独立,可以轻松地添加更多的行为接口;
2.可以轻松地添加更多的行为实现;
例如添加一个用火箭来飞行的行为:添加了一个FlyRocketPowered类,它实现FlyBehavior接口即可
3.具体的行为实现都被封装在XXXBehavior接口内,使用者不用关心具体的行为细节;
4.行为接口 XXXBehavior 可以供其他 client 复用,例如鸡;
整合鸭子的行为:
1.鸭子将飞行和叫的行为委托 (delegate) 给别人处理,而不是在 Duck 类或者子类中自己来实现;
2.在 Duck 类中加入行为实例 xxxBehavior 和行为执行函数 performXxx();
3.实现 performQuack();
public class Duck {QuackBehavior quackBehavior;
}
public void performQuack() {quackBehavior.quack();
}
4.初始化行为实例变量,例如在 MallardDuck 类中:
public class MallardDuck extends Duck {public MallardDuck() {quackBehavior = new Quack();flyBehavior = new FlyWithWings();
}
这里的做法并不完美:因为 MallardDuck 的构造函数里使用了 Quack 类 这个具体实现,即 MallardDuck 和 具体实现类 Quack 绑定在了一起。
由于xxxBehavior是可以在运行时被改变的,所以目前的做法已有足够的弹性了,暂时不用理会构造函数里的瑕疵。
5.允许动态地设置鸭子的行为,添加setXxxBehavior():
public void setFlyBehavior(FlyBehavior fb) {flyBehavior = fb;
}
到这里,模拟鸭子的整个设计就已经完成了,整个设计框图如下:
5. 测试当前代码
测试代码:
public class MiniDuckSimulator {public static void main(String[] args) {Duck mallard = new MallardDuck();mallard.performQuack();mallard.performFly();mallard.setFlyBehavior(new FlyRocketPowered());mallard.performFly();}
}
测试效果:
%java MiniDuckSimulator
Quack
I’m flying!!
I'm flying with a rocker
根据测试结果总结一下:
1."有1个"比“是1个”更好,鸭子的行为不是继承来的,而是和行为对象组合而来;
2.设计原则:多用组合,少用继承(Favor composition over inheritance);
3.模拟鸭子使用的设计模式:策略模式;
什么是策略模式?
指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。
策略模式三要素:
1.定义了一族算法(业务规则);
2.封装了每个算法;
3.这族的算法可互换代替(interchangeable);
再举一个例子:
在一款游戏里,有不同的角色(国王、皇后、骑士...),角色有不同的武器(斧头、剑、刀),该怎么设计?
6. 最后的总结
懒人们专用:
7. 更多实践
有哪些开源项目使用或者借鉴了策略模式?
•Android
还等什么?赶紧分析起来吧~~
你和我各有一个苹果,如果我们交换苹果的话,我们还是只有一个苹果。但当你和我各有一个想法,我们交换想法的话,我们就都有两个想法了。如果你也对嵌入式系统开发有兴趣,并且想和更多人互相交流学习的话,请关注我的公众号:ESexpert,一起来学习吧,欢迎各种收藏/转发/批评。
推荐阅读:
嵌入式编程专辑Linux 学习专辑C/C++编程专辑
Qt进阶学习专辑关注微信公众号『技术让梦想更伟大』,后台回复“m”查看更多内容,回复“加群”加入技术交流群。
长按前往图中包含的公众号关注
从“策略模式”聊聊“设计模式”有多重要?相关推荐
- 从java多态到策略模式_设计模式中的多态——策略模式详解
2. 策略模式详解 2.1 策略模式定义 策略模式定义了一系列算法,并将每一个算法封装起来,而且使它们还可以相互替换.策略模式让算法独立于使用它的客户端而独立的变化. 可以使用多态进行类比来理解策略模 ...
- python策略模式_设计模式(python实现):策略模式
策略模式简单说和小时候我们玩的玩具差不多,一堆零部件通过不同的拼凑构成几个不同的机器人. 1.举个栗子 我们买了一个机器人,同时这个机器人配了三把武器,三把武器可以替换使用 2.Show in Cod ...
- java计数器策略模式_java设计模式(二十一)--策略模式
对于策略模式,我在很多面试题上看到过考察这一类的问题,这种模式也的确比较好用. 我感觉这种模式就是将不同实现的方法放到一个接口中,然后通过实现这个接口来实现不同的运行结果,这种模式有三部分构成: 策略 ...
- 策略模式-大话设计模式
策略模式(Strategy):它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户. 一.需求 实现一个商场收银软件,满足满减.打折.正常收费. 二.代 ...
- 商场促销——策略模式(设计模式)
商场收银时,如何促销,用打折还是返利,其实都是一些算法,用工厂来生成算法对象,这没有错,但算法本身只是一种策略,最重要的是这些算法是随时都可能互相替换的,就这点变化,而封装变化点是我们面向对象的一种很 ...
- java策略模式_Java设计模式之策略模式详解
本文实例为大家分享了Java策略模式,供大家参考,具体内容如下 1.策略模式(Strategy Pattern)是一种比较简单的模式,也叫做政策模式(PolicyPattern). 定义如下: Def ...
- 代理模式 委派模式 策略模式_设计模式 - 委派模式
理解 首先委派模式不属于23种设计模式. 所谓委派,个人理解是:将为达到最终结果的事情交给其他人或中间人来干,我只要最终结果,其他的事情,由我委派的人来安排. 更直白的表达就是,比如,我们想要盖一栋楼 ...
- Java设计模式之行为型:策略模式
一.背景: 在开发中经常遇到这种情况,实现某个功能有多种算法策略,我们可以根据不同环境或者条件选择不同的算法策略来完成该功能,比如查找.排序等,一种常用方式是硬编码在一个类中,如需要提供多种查找算法, ...
- 大话设计模式笔记(二)——商品促销 策略模式
第二章商品促销--策略模式 需求:商品价格计算,并增加折扣条件 工厂模式UML图 在工厂模式中,调用端代码会通过折扣工厂类生成折扣对象,折扣对象调用折扣方法.这里关联了两个类,工厂类和抽象折扣类. 策 ...
最新文章
- 动态数组 allocator
- android中ADT和SDK的关系(转)
- 图片二进制编码_python3从零学习-5.7.4、quopri编码与解码经过MIME转码打印数据
- Atitit.数据索引 的种类以及原理实现机制 索引常用的存储结构
- matlab 子图title的位置_Plotly_多个子图
- Python中的eval(),exec()以及其相关函数
- 2021年信息系统项目管理师案例分析第二题讲解
- CG CTF WEB 变量覆盖
- mysql 数据库 额外_mysql – 拥有“额外”数据库查询有多糟糕?
- SQL注入——SQLmap的进阶使用(十三)
- c++对数函数_DS-K1T105M-C 海康威视考勤门禁一体机 支持刷卡+密码 DS-K1T105E/M/C-C
- DOM属性用法速查手册
- Qt学习之路(54): 自定义拖放数据对象
- 固定资产中计算机软件类型,国税局固定资产的分类
- ajax教程初始模板,ajax实战入门模板
- linux更改jdk版本
- 普通话-命题说话11-20
- Packet Data Convergence Protocol (PDCP)阅读笔记
- asp.net909-大型社区包裹代收与分发系统
- chart.js使用学习——散点图