策略模式在实际开发过程中其实非常的常见,那么本章也从原始需求扩展到设计模式上是如何更好的落地的。

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、总结

我们可以假想,一个鸭子可以有很多子类。如果把方法全部写在父类。子类都会继承它,对于不同的子类,有些方法违反了逻辑成为了冗余(不应该出现在子类中)。

        那是不是就没有缺点了呢?当然有,在调用端必须要知道所有的这些行为,否则无法在任何场合决定调用行为的什么结果,而对于很多场景需求中,我们并不明确的知道下一个需求是什么,即不知道会存在多少个行为策略类,因为每个行为策略都会有个类出现,如果被多处调用,就必须要知道所有的策略场景,维护也不是很方便。

        下一章节我们讲述装饰者模式。

设计模式篇之——策略设计模式相关推荐

  1. 设计模式篇之——命令设计模式

    命令设计模式很多人看了官方的文档是不够清晰的,甚至看了一遍基本记不住,说简单的谈不上,说难的话就那么一点代码,所以思想很重要,经过自己摸索后的一些理解,本文用最形象深刻的例子来带大家深刻理解命令设计模 ...

  2. Java设计模式(一):策略设计模式

    1. 应用场景 当系统能在几种算法中快速地切换,或系统中有一些类,它们仅行为不同时,或系统中存在多重条件选择语句时,可以考虑采用策略模式.找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变 ...

  3. 单例模式访问mysql设计类图_如何应用策略设计模式分离JDBC数据库连接中的外部环境信息...

    软件项目实训及课程设计指导--如何应用策略设计模式分离JDBC数据库连接中的外部环境信息 1.什么是策略(Strategy)设计模式 策略设计模式把"算法"(也就是软件应用系统中的 ...

  4. 设计模式:策略设计模式

    一.什么是策略设计模式 1.1 策略设计模式定义 策略设计模式(Strategy Pattern)是一种定义一系列算法的方法,从概念上来看,所有这些算法完成的都是相同的工作,只是实现不同,它可以让算法 ...

  5. java状态模式和策略模式_Java状态和策略设计模式之间的差异

    java状态模式和策略模式 为了在Core Java应用程序中正确使用状态和策略设计模式,对于Java开发人员清楚地了解它们之间的区别很重要. 尽管状态和策略设计模式的结构相似,并且都基于开放式封闭设 ...

  6. Java状态和策略设计模式之间的差异

    为了在Core Java应用程序中正确使用状态和策略设计模式,对于Java开发人员清楚地了解它们之间的区别很重要. 尽管状态和策略设计模式的结构相似,并且都基于开放式封闭设计原则,从SOLID设计原则 ...

  7. 程序员内功-设计模式篇

    一. 什么是设计模式 纠结了好久,今天终于下定决心开始写设计模式系列,因为这个系列章节确实不好写,在这之前,也看了好多关于设计模式的博客.视频.书籍等,最后结合自己的理解,亲自动手实操代码,完成该章节 ...

  8. 【设计模式-适配器,策略模式,和责任链】

    文章目录 一.适配器模式(Adaptor Pattern) 1. 定义 2. 生活例子(百度) 3. 适配器角色 4. 适配器模式分类 5. 实例 二.策略模式(Strategy Pattern) 1 ...

  9. 设计模式 ( 十八 ) 策略模式Strategy(对象行为型)

    设计模式 ( 十八 ) 策略模式Strategy(对象行为型) 1.概述 在软件开发中也经常遇到类似的情况,实现某一个功能有多种算法或者策略,我们能够依据环境或者条件的不同选择不同的算法或者策略来完毕 ...

最新文章

  1. spyder ipython控制台_Spyder Ipython控制台完全忽略打印语句
  2. Linux命令行下登录ssl加密的ftp
  3. mongodb简介、安装、启停(转并学习)
  4. Intel Realsense D435报错 RuntimeError: MFCreateDeviceSource(_device_attrs, _source) returned: HResult
  5. 如何安全的存储用户密码?(中)代码篇
  6. 荧光共定位定量分析,单通道散点图剖析
  7. OpenCV 高级API:TextDetectionModel和TextRecognitionModel
  8. Linux历史,安装,分区,版本
  9. Java BigInteger类| toByteArray()方法与示例
  10. VSCode搭建vue前端开发工程的配置文件-launch.json
  11. 浏览器极速模式和兼容模式差异
  12. 【预测模型】BP神经网络的预测
  13. Oracle VM VirtualBox 打开Ubuntu出现0x00000000指令引用的0x00000000内存,该内存不能为written的解决方案
  14. 过滤器把样式过滤掉,无法显示样式问题, 处理方法
  15. wow私服,arcemu trunk源码编译架设
  16. 第三版新视野大学英语读写教程4结业考点(1,2,3,5,6单元)
  17. 漫天杂想系列之五:2018年总结
  18. 解决Skype一台电脑登陆多个账号的问题
  19. mysql老司机之路
  20. word表格分页时怎样能自动生成表头

热门文章

  1. Google排名第一的技术,引数十万人关注!网友:差点我就放弃了!
  2. 微信9年:张小龙指明方向,微信AI全面开放NLP能力
  3. 华为腾讯百度众安微众360大咖齐聚,2019中国区块链开发者大会首批议程曝光!...
  4. 数据库“新解”,看这里,get!
  5. 顶尖技术专家严选,15场前沿论坛思辨,2019中国大数据技术大会邀您共赴
  6. 倒计时1天!「2019 Python开发者日」报名即将关闭(附参会提醒)
  7. PFLD:简单、快速、超高精度人脸特征点检测算法
  8. 如何优雅地拿到30k月薪的offer?这几个大咖就是来帮你搞定薪水和面试官的
  9. 能解决80%故障的排查思路
  10. 为什么不建议你用a.equals(b)判断对象相等