设计模式篇之——策略设计模式
策略模式在实际开发过程中其实非常的常见,那么本章也从原始需求扩展到设计模式上是如何更好的落地的。
1、定义
分别封装行为接口,实现算法族,父类里放行为接口对象,在子类里具体设定行为对象。一个类的行为或其算法可以在运行时更改,这种类型的设计模式属于行为型模式。
定义总是模糊的,用大白话来说,我们把每个要做的事情称为【行为】,每一个行为都应该被抽象成一个一个接口,和这些行为的使用者进行解耦。举个例子,比如鸭子这个抽象父类存在很多的行为方法,鸭子会游泳,会叫,会很多本领;每个不同的鸭子都要去继承这个抽象鸭子父类,每个鸭子叫声不同,需要对父类的叫方法进行重写。看起来是没问题,如果增加了额外的需求,比如鸭子要飞,那么很可能所有的子类都要去必须要重写飞,但是不是所有鸭子都会飞。一旦鸭子种类多起来,改动就会很大,我们需要的效果是,具体要哪个鸭子做什么,不应该所有的鸭子都被影响。
既然很离谱,那么我们分析下,变动的东西是不是一些特性?比如飞,不是所有的鸭子都会飞,不是所有的鸭子都会跳舞(比如唐老鸭),我们假定每个鸭子都会游泳。那么抽离出来个性,不变的是共性,即抽象是共性,接口是特性。
灵魂画师又来了:
2、案例讲解
组成部分我就不说了,上面的图就表明了哪些组成部分,正式进入需求:
产品经理:那个老王,你帮我做个功能,我要两个鸭子,黑鸭和红鸭子,这两个鸭子会叫、会飞、会游泳哈,区别是黑鸭和红鸭子的颜色不一样(这不是废话么)。
这个时候我们用OOP思想(面向对象编程),定义一个鸭子父类。
/*** @Description: 设计一个抽象类鸭子* @title: Duck* @Author Star_Chen* @Date: 2021/12/21 22:36* @Version 1.0*/ public abstract class Duck {public Duck() {}/*** @Date: 2021/12/21 22:39* @Description: 抽象的自我介绍颜色方法让子类实现*/public abstract void perform();/*** @Date: 2021/12/21 22:39* @Description: 本抽象父类中自己实现游泳方法,子类也可以自己实现*/public void swim(){System.out.println("我是个鸭子,会游泳~");}/*** @Date: 2021/12/21 22:46* @Description: 本抽象父类中自己实现叫的方法,子类也可以自己实现*/public void quack(){System.out.println("我是鸭子,我会叫呱呱呱!");} }
来一个红鸭子
/*** @Description: 红鸭子* @title: RedDuck* @Author Star_Chen* @Date: 2021/12/21 22:40* @Version 1.0*/ public class RedDuck extends Duck {@Overridepublic void perform() {System.out.println("我是红色的鸭子!");} }
再来一个黑鸭子
/*** @Description: 黑鸭子* @title: BlackDuck* @Author Star_Chen* @Date: 2021/12/21 22:41* @Version 1.0*/ public class BlackDuck extends Duck {@Overridepublic void perform() {System.out.println("我是黑色的鸭子!");} }
来个Main函数调用
/*** @Description:* @title: DuckMain* @Author Star_Chen* @Date: 2021/12/21 22:44* @Version 1.0*/ public class DuckMain {public static void main(String[] args) {RedDuck redDuck = new RedDuck();BlackDuck blackDuck = new BlackDuck();redDuck.quack();redDuck.perform();redDuck.swim();System.out.println("<==========================>");blackDuck.quack();blackDuck.perform();blackDuck.swim();} }
输出结果很简单
我是鸭子,我会叫呱呱呱! 我是红色的鸭子! 我是个鸭子,会游泳~ <==========================> 我是鸭子,我会叫呱呱呱! 我是黑鸭子! 我是个鸭子,会游泳~
这个时候产品经理说,对了给我再来两个鸭子,让鸭子飞,但是呢我只让黑鸭子飞和xxx鸭子飞,对了我还要不同的鸭子叫的不一样,红鸭子geigeigei,黑鸭子一给我里giaogiao...
想一下,如果在父类写fly方法,定义成抽象方法,那么所有继承父类的鸭子,都要添加fly方法,但是不是所有鸭子都会飞呀,违背逻辑。那如果不定义成抽象方法,定义成父类的普通方法,子类的所有鸭子,要想实现就必须重写父类的fly,或者要么就调用父类的fly,但是实际中,比如北京烤鸭都没有飞的概念,怎么能让子类具有这样的方法呢?显然这是不可能的
父类挖的一个坑,每个子类都要来填,增加工作量,复杂度O(N^2)。不是好的设计方式。这时候,我们应该考虑哈继承的弊端了。使用接口就可以很好的解决这个问题。(思路:继承是实现共性,减少代码的重复。接口是实现特性。)
我们采用策略模式来做
分析:
1、项目变化与不变部分,提取变化部分,抽象成接口+实现;(抽象是共性,接口是特性)
2、鸭子那些功能是会根据新需求变化的?叫声、飞行
定义两个变化的行为接口
FlyBehavior和QuackBehavior
定义飞的行为
/*** @Description:* @title: FlyBehavior* @Author Star_Chen* @Date: 2021/12/21 23:53* @Version 1.0*/ public interface FlyBehavior {/*** @Date: 2021/12/21 23:54* @Description: 飞的行为*/void fly(); }
定义叫的行为
/*** @Description:* @title: QuackBehavior* @Author Star_Chen* @Date: 2021/12/22 0:00* @Version 1.0*/ public interface QuackBehavior {/*** @Date: 2021/12/22 0:01* @Description: 叫的行为*/void quack(); }
那么Duck父类我们就要调整,只要涉及到个性的东西,比如fly,quack,都要以行为去做变更。
/*** @Description: 设计一个抽象类鸭子* @title: Duck* @Author Star_Chen* @Date: 2021/12/21 22:36* @Version 1.0*/ public abstract class Duck {//具备抽象行为FlyBehavior flyBehavior;QuackBehavior quackBehavior;/*** @Date: 2021/12/22 0:07* @Description: 实例化对象时可以动态的改变对象的行为(比继承灵活性强)*/public void setFlyBehavior(FlyBehavior flyBehavior) {this.flyBehavior = flyBehavior;}/*** @Date: 2021/12/22 0:07* @Description: 实例化对象时可以动态的改变对象的行为(比继承灵活性强)*/public void setQuackBehavior(QuackBehavior quackBehavior) {this.quackBehavior = quackBehavior;}/*** @Date: 2021/12/21 22:46* @Description: 本抽象父类中自己实现叫的方法,子类也可以自己实现*/public void quack(){ // System.out.println("我是鸭子,我会叫呱呱呱!");quackBehavior.quack();}public void fly(){flyBehavior.fly();}/*** @Date: 2021/12/21 22:39* @Description: 抽象的自我介绍颜色方法让子类实现*/public abstract void perform();/*** @Date: 2021/12/21 22:39* @Description: 本抽象父类中自己实现游泳方法,子类也可以自己实现*/public void swim(){System.out.println("我是个鸭子,会游泳~");} }
叫行为的实现类
/*** @Description: giaogiao的叫* @title: GiaoQuackBehavior* @Author Star_Chen* @Date: 2021/12/22 0:01* @Version 1.0*/ public class GiaoQuackBehavior implements QuackBehavior {@Overridepublic void quack() {System.out.println("一给我里giaogiao的叫!");} }/*** @Description: geigei的叫* @title: UglyQuackBehavior* @Author Star_Chen* @Date: 2021/12/22 0:01* @Version 1.0*/ public class UglyQuackBehavior implements QuackBehavior {@Overridepublic void quack() {System.out.println("geigei的叫!");} }
飞行为的实现类
/*** @Description: 低飞* @title: LowFlyBehavior* @Author Star_Chen* @Date: 2021/12/21 23:55* @Version 1.0*/ public class LowFlyBehavior implements FlyBehavior {@Overridepublic void fly() {System.out.println("鸭子会低飞!");} }/*** @Description: 高飞* @title: HighFlyBehavior* @Author Star_Chen* @Date: 2021/12/21 23:54* @Version 1.0*/ public class HighFlyBehavior implements FlyBehavior {@Overridepublic void fly() {System.out.println("鸭子会高飞!");} }
我们模拟鸭子主函数,还是实现上面新增的需求:
红鸭子叫geigeigei,黑鸭子叫一给我里giaogiao
红鸭子高飞,黑鸭子低飞
在调用方面我们就这么写:
/*** @Description:* @title: DuckMain* @Author Star_Chen* @Date: 2021/12/21 22:44* @Version 1.0*/ public class DuckMain {public static void main(String[] args) {//父类为Duck,屏蔽了超类的差别性Duck redDuck = new RedDuck();Duck blackDuck = new BlackDuck();redDuck.perform();redDuck.fly();System.out.println("<==========================>");blackDuck.perform();blackDuck.quack();} }
输出结果:
我是红色的鸭子! 鸭子会高飞! <==========================> 我是黑色的鸭子! 一给我里giaogiao的叫!
如果我想自定义在对象的实例化的时候同时对行为进行重写,那么可以通过setBehavior来实现。
/*** @Description:* @title: DuckMain* @Author Star_Chen* @Date: 2021/12/21 22:44* @Version 1.0*/ public class DuckMain {public static void main(String[] args) {//父类为Duck,屏蔽了超类的差别性Duck redDuck = new RedDuck();Duck blackDuck = new BlackDuck();redDuck.perform();redDuck.setFlyBehavior(new FlyBehavior(){@Overridepublic void fly() {System.out.println("红鸭子我不飞了");}});redDuck.fly();System.out.println("<==========================>");blackDuck.perform();blackDuck.setQuackBehavior(new QuackBehavior() {@Overridepublic void quack() {System.out.println("黑鸭子我不叫了");}});blackDuck.quack();} }
以上代码都是java中的基础知识。运用设计模式中的策略模式。把变化的部分提取出来变为接口+实现。其中,main方法中,父类为Dock基类,是为了屏蔽子类的超类Dock的差别性。Duck类中的SetQuackBehavoir()方法,灵活的让实例化对象灵活的改变对象的行为。比如,绿头鸭,使用了SetQuackBehavoir()方法,定制了自己的quck()方法。因为不是每只鸭都能叫的,叫的是当前鸭的特性。
3、总结
我们可以假想,一个鸭子可以有很多子类。如果把方法全部写在父类。子类都会继承它,对于不同的子类,有些方法违反了逻辑成为了冗余(不应该出现在子类中)。
那是不是就没有缺点了呢?当然有,在调用端必须要知道所有的这些行为,否则无法在任何场合决定调用行为的什么结果,而对于很多场景需求中,我们并不明确的知道下一个需求是什么,即不知道会存在多少个行为策略类,因为每个行为策略都会有个类出现,如果被多处调用,就必须要知道所有的策略场景,维护也不是很方便。
下一章节我们讲述装饰者模式。
设计模式篇之——策略设计模式相关推荐
- 设计模式篇之——命令设计模式
命令设计模式很多人看了官方的文档是不够清晰的,甚至看了一遍基本记不住,说简单的谈不上,说难的话就那么一点代码,所以思想很重要,经过自己摸索后的一些理解,本文用最形象深刻的例子来带大家深刻理解命令设计模 ...
- Java设计模式(一):策略设计模式
1. 应用场景 当系统能在几种算法中快速地切换,或系统中有一些类,它们仅行为不同时,或系统中存在多重条件选择语句时,可以考虑采用策略模式.找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变 ...
- 单例模式访问mysql设计类图_如何应用策略设计模式分离JDBC数据库连接中的外部环境信息...
软件项目实训及课程设计指导--如何应用策略设计模式分离JDBC数据库连接中的外部环境信息 1.什么是策略(Strategy)设计模式 策略设计模式把"算法"(也就是软件应用系统中的 ...
- 设计模式:策略设计模式
一.什么是策略设计模式 1.1 策略设计模式定义 策略设计模式(Strategy Pattern)是一种定义一系列算法的方法,从概念上来看,所有这些算法完成的都是相同的工作,只是实现不同,它可以让算法 ...
- java状态模式和策略模式_Java状态和策略设计模式之间的差异
java状态模式和策略模式 为了在Core Java应用程序中正确使用状态和策略设计模式,对于Java开发人员清楚地了解它们之间的区别很重要. 尽管状态和策略设计模式的结构相似,并且都基于开放式封闭设 ...
- Java状态和策略设计模式之间的差异
为了在Core Java应用程序中正确使用状态和策略设计模式,对于Java开发人员清楚地了解它们之间的区别很重要. 尽管状态和策略设计模式的结构相似,并且都基于开放式封闭设计原则,从SOLID设计原则 ...
- 程序员内功-设计模式篇
一. 什么是设计模式 纠结了好久,今天终于下定决心开始写设计模式系列,因为这个系列章节确实不好写,在这之前,也看了好多关于设计模式的博客.视频.书籍等,最后结合自己的理解,亲自动手实操代码,完成该章节 ...
- 【设计模式-适配器,策略模式,和责任链】
文章目录 一.适配器模式(Adaptor Pattern) 1. 定义 2. 生活例子(百度) 3. 适配器角色 4. 适配器模式分类 5. 实例 二.策略模式(Strategy Pattern) 1 ...
- 设计模式 ( 十八 ) 策略模式Strategy(对象行为型)
设计模式 ( 十八 ) 策略模式Strategy(对象行为型) 1.概述 在软件开发中也经常遇到类似的情况,实现某一个功能有多种算法或者策略,我们能够依据环境或者条件的不同选择不同的算法或者策略来完毕 ...
最新文章
- spyder ipython控制台_Spyder Ipython控制台完全忽略打印语句
- Linux命令行下登录ssl加密的ftp
- mongodb简介、安装、启停(转并学习)
- Intel Realsense D435报错 RuntimeError: MFCreateDeviceSource(_device_attrs, _source) returned: HResult
- 如何安全的存储用户密码?(中)代码篇
- 荧光共定位定量分析,单通道散点图剖析
- OpenCV 高级API:TextDetectionModel和TextRecognitionModel
- Linux历史,安装,分区,版本
- Java BigInteger类| toByteArray()方法与示例
- VSCode搭建vue前端开发工程的配置文件-launch.json
- 浏览器极速模式和兼容模式差异
- 【预测模型】BP神经网络的预测
- Oracle VM VirtualBox 打开Ubuntu出现0x00000000指令引用的0x00000000内存,该内存不能为written的解决方案
- 过滤器把样式过滤掉,无法显示样式问题, 处理方法
- wow私服,arcemu trunk源码编译架设
- 第三版新视野大学英语读写教程4结业考点(1,2,3,5,6单元)
- 漫天杂想系列之五:2018年总结
- 解决Skype一台电脑登陆多个账号的问题
- mysql老司机之路
- word表格分页时怎样能自动生成表头
热门文章
- Google排名第一的技术,引数十万人关注!网友:差点我就放弃了!
- 微信9年:张小龙指明方向,微信AI全面开放NLP能力
- 华为腾讯百度众安微众360大咖齐聚,2019中国区块链开发者大会首批议程曝光!...
- 数据库“新解”,看这里,get!
- 顶尖技术专家严选,15场前沿论坛思辨,2019中国大数据技术大会邀您共赴
- 倒计时1天!「2019 Python开发者日」报名即将关闭(附参会提醒)
- PFLD:简单、快速、超高精度人脸特征点检测算法
- 如何优雅地拿到30k月薪的offer?这几个大咖就是来帮你搞定薪水和面试官的
- 能解决80%故障的排查思路
- 为什么不建议你用a.equals(b)判断对象相等