Java设计模式(学习整理)---策略模式
1. 模式定义
把会变化的内容取出并封装起来,以便以后可以轻易地改动或扩充部分,而不影响不需要变化的其他部分;
2.模式本质:
少用继承,多用组合,简单地说就是:固定不变的信息封装在一个类中,变化的信息我们使用接口,抽象定义,那么使用的时候:继承不变的,自定义实现变化的那 部分!
3.举例分析:
示例:
一个鸭子类型: 抽象类型
/*抽象的鸭子类*/ 1 public abstract class Duck { 2 //所有的鸭子均会叫以及游泳,所以父类中处理这部分代码 3 public void quack() { 4 System.out.println("嘎嘎嘎....."); 5 } 6 7 public void swim() { 8 System.out.println("游啊游......."); 9 } 10 11 //因为每种鸭子的外观是不同的,所以父类中该方法是抽象的,由子类型自己完成。 12 public abstract void display(); 13 }
具体鸭子的继承子类:
1 public class MallardDuck extends Duck { 2 //野鸭外观显示为绿头 3 public void display() { 4 System.out.println("我是绿头鸭子......"); 5 } 6 } 7 8 public class RedHeadDuck extends Duck { 9 //红头鸭显示为红头 10 public void display() { 11 System.out.println("我是红头鸭子......"); 12 } 13 } 14 15 public class RubberDuck extends Duck { 16 //橡皮鸭叫声为嘎嘎嘎叫,所以重写父类以改写行为 17 public void quack() { 18 System.out.println("嘎嘎嘎......."); 19 } 20 21 //橡皮鸭显示为黄头 22 public void display() { 23 System.out.println("我是黄头鸭子......."); 24 } 25 }
/***************************【分析说明】***************************************/ 上述代码,初始实现得非常好。现在我们如果给Duck.java中加入fly()方法的话,那么在子类型中均有了该方法,于是我们看到了 会飞的橡皮鸭子,你看过吗?当然,我们可以在子类中通过空实现重写该方法以解决该方法对于子类型的影响。但是父类中再增加其它的方法呢?通过继承在父类中提供行为,会导致以下缺点:a. 代码在多个子类中重复;b. 运行时的行为不容易改变;c. 改变会牵一发动全身,造成部分子类型不想要的改变;/******************************************************************************/
好啦,还是刚才鸭子的例子,你也许想到使用接口,将飞的行为、叫的行为定义为接口,然后让Duck的各种子类型实现这些接口。
这时侯代码类似于:
1 public abstract class Duck { 2 //将变化的行为 fly() 以及quake()从Duck类中分离出去定义形成接口,有需求的子类中自行去实现 3 4 public void swim() { 5 System.out.println("游啊游......."); 6 } 7 8 public abstract void display(); 9 } 10 11 //变化的 fly() 行为定义形成的接口 12 public interface FlyBehavior { 13 void fly(); 14 } 15 16 //变化的 quack() 行为定义形成的接口 17 public interface QuackBehavior { 18 void quack(); 19 } 20 21 //野鸭子会飞以及叫,所以实现接口FlyBehavior, QuackBehavior 22 public class MallardDuck extends Duck implements FlyBehavior, QuackBehavior{ 23 public void display() { 24 System.out.println("我是绿头鸭......."); 25 } 26 27 public void fly() { 28 System.out.println("Fly."); 29 } 30 31 public void quack() { 32 System.out.println("嘎嘎嘎:绿鸭子叫........"); 33 } 34 } 35 36 //红头鸭子会飞以及叫,所以也实现接口FlyBehavior, QuackBehavior 37 public class RedHeadDuck extends Duck implements FlyBehavior, QuackBehavior{ 38 public void display() { 39 System.out.println("我是红头鸭......"); 40 } 41 42 public void fly() { 43 System.out.println("飞呀飞......."); 44 } 45 46 public void quack() { 47 System.out.println("嘎嘎嘎:红鸭子叫"); 48 } 49 } 50 51 //橡皮鸭不会飞,但会嘎嘎嘎叫,所以只实现接口QuackBehavior 52 public class RubberDuck extends Duck implements QuackBehavior{ 53 //橡皮鸭叫声为嘎嘎嘎叫 54 public void quack() { 55 System.out.println("嘎嘎嘎:橡皮鸭叫......"); 56 } 57 58 //橡皮鸭显示为黄头 59 public void display() { 60 System.out.println("我是黄头鸭......"); 61 } 62 }
分析:
上述代码虽然解决了一部分问题,让子类型可以有选择地提供一些行为(例如 fly() 方法将不会出现在橡皮鸭中).但我们也看到,野鸭子MallardDuck.java和红头鸭子RedHeadDuck.java的一些相同行为代码不能得到重复使用。很大程度上这是从一个火坑跳到另一个火坑。在一段程序之后,让我们从细节中跳出来,关注一些共性问题。不管使用什么语言,构建什么应用,在软件开发上,一直伴随着的不变的真理是:需要一直在变化。不管当初软件设计得多好,一段时间之后,总是需要成长与改变,否则软件就会死亡。我们知道,继承在某种程度上可以实现代码重用,但是父类(例如鸭子类Duck)的行为在子类型中是不断变化的,让所有子类型都有这些行为是不恰当的。我们可以将这些行为定义为接口,让Duck的各种子类型去实现,但接口不具有实现代码,所以实现接口无法达到代码复用。这意味着,当我们需要修改某个行为,必须往下追踪并在每一个定义此行为的类中修改它,一不小心,会造成新的错误。
设计原则:
设计原则: 把应用中变化的地方独立出来,不要和那些不需要变化的代码混在一起。这样代码变化引起的不经意后果变少,系统变得更有弹性。按照上述设计原则,我们重新审视之前的Duck代码。1) 分开变化的内容和不变的内容Duck类中的行为 fly(), quack(), 每个子类型可能有自己特有的表现,这就是所谓的变化的内容。Duck类中的行为 swim() 每个子类型的表现均相同,这就是所谓不变的内容。我们将变化的内容从Duck()类中剥离出来单独定义形成接口以及一系列的实现类型。将变化的内容定义形成接口可实现变化内容和不变内容的剥离。其实现类型可实现变化内容的重用。这些实现类并非Duck.java的子类型,而是专门的一组实现类,称之为"行为类"。由行为类而不是Duck.java的子类型来实现接口。这样,才能保证变化的行为独立于不变的内容。
于是我们有:
1 //变化的 fly() 行为定义形成的接口 2 public interface FlyBehavior { 3 void fly(); 4 } 5 6 //变化的 fly() 行为的实现类之一 7 public class FlyWithWings implements FlyBehavior { 8 public void fly() { 9 System.out.println("飞呀飞......"); 10 } 11 } 12 13 //变化的 fly() 行为的实现类之二 14 public class FlyNoWay implements FlyBehavior { 15 public void fly() { 16 System.out.println("我翅膀受伤了,飞不了......"); 17 } 18 }
1 //变化的 quack() 行为定义形成的接口 2 public interface QuackBehavior { 3 void quack(); 4 } 5 6 //变化的 quack() 行为实现类之一 7 public class Quack implements QuackBehavior { 8 public void quack() { 9 System.out.println("嘎嘎嘎......"); 10 } 11 } 12 13 //变化的 quack() 行为实现类之二 14 public class Squeak implements QuackBehavior { 15 public void quack() { 16 System.out.println("吱吱吱......."); 17 } 18 } 19 20 //变化的 quack() 行为实现类之三 21 public class MuteQuack implements QuackBehavior { 22 public void quack() { 23 System.out.println("哑巴,不会叫......."); 24 } 25 }
通过以上设计,fly()行为以及quack()行为已经和Duck.java没有什么关系,可以充分得到复用。而且我们很容易增加新的行为, 既不影响现有的行为,也不影响Duck.java。但是,大家可能有个疑问,就是在面向对象中行为不是体现为方法吗?为什么现在被定义形成类(例如Squeak.java)?在OO中,类代表的"东西"一般是既有状态(实例变量)又有方法。只是在本例中碰巧"东西"是个行为。既使是行为,也有属性及方法,例如飞行行为,也需要一些属性记录飞行的状态,如飞行高度、速度等。
整合变化的内容和不变的内容:
1 public abstract class Duck { 2 //将行为类声明为接口类型,降低对行为实现类型的依赖 3 FlyBehavior flyBehavior; 4 QuackBehavior quackBehavior; 5 6 public void performFly() { 7 //不自行处理fly()行为,而是委拖给引用flyBehavior所指向的行为对象 8 flyBehavior.fly(); 9 } 10 11 public void performQuack() { 12 quackBehavior.quack(); 13 } 14 15 public void swim() { 16 System.out.println("游啊游......"); 17 } 18 19 public abstract void display(); 20 }
Duck.java不关心如何进行 fly()以及quack(), 这些细节交由具体的行为类完成。
1 public class MallardDuck extends Duck{ 2 public MallardDuck() { 3 flyBehavior=new FlyWithWings(); 4 quackBehavior=new Quack(); 5 } 6 7 public void display() { 8 System.out.println("Green head."); 9 } 10 }
测试类:
1 public class DuckTest { 2 public static void main(String[] args) { 3 Duck duck=new MallardDuck(); 4 duck.performFly(); 5 duck.performQuack(); 6 } 7 }
4.思想重点:
(1)策略思想:继承,可以实现静态代码的复用; 组合,可以实现代码的弹性维护; 使用组合代替继承,可以使代码更好地适应软件开发完后的需求变化。 (2)策略模式的本质: 少用继承,多用组合
转载于:https://www.cnblogs.com/newwind/p/5653097.html
Java设计模式(学习整理)---策略模式相关推荐
- Java设计模式学习 - 模版方法模式策略模式
个人博客项目地址 希望各位帮忙点个star,给我加个小星星✨ 设计模式-模板方法&策略模式 简单介绍 模板方法模式(Template):定义一个操作中的算法的骨架,而将一些步骤延迟到子类中. ...
- Java设计模式学习记录-解释器模式
前言 这次介绍另一个行为模式,解释器模式,都说解释器模式用的少,其实只是我们在日常的开发中用的少,但是一些开源框架中还是能见到它的影子,例如:spring的spEL表达式在解析时就用到了解释器模式,以 ...
- Java设计模式之十一 ---- 策略模式和模板方法模式
前言 在上一篇中我们学习了行为型模式的访问者模式(Visitor Pattern)和中介者模式(Mediator Pattern).本篇则来学习下行为型模式的两个模式,策略模式(Strategy Pa ...
- 设计模式学习:策略模式
策略模式简介 策略模式:策略模式是一种行为型模式,它将对象和行为分开,将行为定义为 一个行为接口 和 具体行为的实现.策略模式最大的特点是行为的变化,行为之间可以相互替换.每个if判断都可以理解为就是 ...
- Java设计模式6:策略模式
策略模式 策略模式的用意是针对一组算法,将每一个算法封装到具有共同接口的独立类中,从而使得它们可以相互替换.策略模式使得算法可以在不影响到客户端的情况下发生变化. 策略模式的结构 策略模式是对算法的包 ...
- [设计模式学习笔记] -- 策略模式
策略模式 定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户. 举一个简单的例子来描述策略模式. 设计一款冷兵器时代士兵打仗的游戏,游戏内部设计要使用OO技术. ...
- java设计模式之【策略模式】
策略模式 策略模式定义了算法族,分别封装起来,让他们之间可以相互替换,此模式让算法的变化独立于使用算法的客户. 开启策略模式 我们的的代码中有各种鸭子 突然有一天,我们的需求变了.... 但是这也带来 ...
- 设计模式学习01策略模式记录
(个人记录)策略模式带来的好处就是更加的有弹性,可以很方便的动态改变对象的行为,在已经固定的项目中如果要增加新的类型,在项目中我们要分析变化部分与不变部分. 将变化的部分(也就是策略算法)使用接口的方 ...
- 设计模式学习之策略模式(Strategy,行为型模式)(13)
转载地址:http://www.cnblogs.com/zhili/p/StragetyPattern.html 一.引言 本文要介绍的策略模式也就是对策略进行抽象,策略的意思就是方法,所以也就是对方 ...
- Java 设计模式情景分析——策略模式
当实现某功能需要根据实际情况选择不同的算法或者策略时,可以选择通过硬编码的方式(if-else 或者 switch-case)来实现,但是这样会使这个类变得臃肿,维护成本上升,出错率也变大了.基于这样 ...
最新文章
- 科大星云诗社动态20210420
- mysql 存储过程 条件_mysql sql存储过程条件定义与处理
- 阿里云ECS服务器多种实例规格如何选择
- 关于tag,viewWithTag
- Linux rm 删除指定文件外的其他文件 方法汇总
- ubuntu安装hive2.3.7
- Backbone.js入门学习资源
- 什么是.NET Framework
- 详解2021华为笔试三道编程题
- Hexo + GitHub搭建个人博客 --- Standard Edition
- 二值图像数字水印技术的实现
- 安卓手机修改ntp服务器,修改安卓手机ntp服务器地址
- 3种内网穿透方式连接家用宽带服务器
- opengl介绍 webGL Open Inventor、Cosmo3D、Optimizer 3DLabs
- 知道创宇入选第九届CNCERT国家级网络安全应急服务支撑单位
- 程序员快速成长的核心原则
- 初学者LDPC码扫盲
- (转)SwitchyOmega规则列表
- 用Python写DES加解密的常用函数
- 除了ChatGPT,跨境电商必备的五款AI工具
热门文章
- 简单易懂的 pwnable.kr 第一题[fd]Writeupt
- Java线程之守护线程(Daemon) .
- centos7编译安装php7.3
- 都是套路:高并发系统的降级特技
- Ubuntu字符界面输入密码始终提示错误 login incorrect 解决办法
- 启动Nginx 出现 nginx: [emerg] unknown directive 锘?user 错误
- 如何在单元测试中测试异步函数,block回调这种
- [Everyday Mathematics]20150203
- 模糊查询实例 只要相关匹配即可
- 使用ImitateLogin模拟登录百度