(四)、行为型模式(11种)
行为型模式用于描述程序在运行时复杂的流程控制
,即描述多个类或对象之间怎样相互协助共同完成单个对象都无法独特完成的任务,它设计算法与对象间职责的分配。
行为型模式分为类行为模式和对象行为模式,前者采用继承机制
来在类
间分配行为,后者采用组合或聚合
对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足"合成复用原则",所以对象行为模式比类行为模式具有更强大的灵活性
。
除了"模板方法模式"和解释器模式是类行为模式,其他的全部属于对象行为型模式。
1.模板方法模式
(1).概述
在面向对象程序设计过程中,程序员常常会遇到这种情况:设计一个系统时知道了算法所需要的关键步骤,而且确定了这些步骤的执行顺序,但某些步骤的具体实现还未知,或者说某些步骤的实现与具体的环境相关。
列如: 去银行办理业务一般要经历四个流程: 区号、排队、办理具体业务、对银行工作人员进行分析等,其中取号、排队和对银行共工作人员进行评分的业务对每个客户都是一样的
,可以在父类中实现,但是办理具体业务
却因人而异,它可能是存款、取款或者转账等,可以延迟到子类中实现。
定义:
定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法得某些特定步骤
。
(2).结构
模板方法模式包含以下主要角色:
- 抽象类:负责给出一个算法的轮廓和骨架。它有一个
模板方法和若干个基本方法
构成。
模板方法
: 定义了算法的骨架,按某种算法调用其包含的基本方法
。基本方法
: 是实现算法各个步骤的方法,是模板方法的组成部分。基本方法又可以分为三种
- (1).
抽象方法(办理具体业务)
: 一个抽象方法由抽象类声明、由其具体子类实现 - (2).
具体方法(取号、排队、评分)
:一个具体方法由一个抽象类或具体类声明并实现,其子类可以进行覆盖也可以直接继承 - (3).
钩子方法
: 在抽象类中以及该实现,包括用于判断的逻辑方法和需要子类重写的空方法两种。一般钩子方法是用于判断的逻辑方法,这类方法名一般为isXxx,返回值类型为Boolean类型。
- 具体子类: 实现抽象类中所定义的抽象方法和钩子方法,它们是一个顶级逻辑的组成步骤。
(3).案列实现
eg: 炒菜
炒菜的步骤是固定的,分为倒油、热油、到蔬菜、倒调料品、翻炒等步骤。现通过模板方法模式来用代码模拟。
抽象类
package com.jsxs.behavioralModel.template; /** * @Author Jsxs * @Date 2023/4/22 20:32 * @PackageName:com.jsxs.behavioralModel.template * @ClassName: AbstractClass * @Description: TODO 抽象类(模板方法和基本方法) * @Version 1.0 */ public abstract class AbstractClass { // 模板方法定义 (算法结构不能被子类改变) public final void cookProcess(){ pourOil(); heatOil(); pourVegetable(); pourSauce(); } // 倒油 public void pourOil() { System.out.println("倒油"); } // 热油 public void heatOil() { System.out.println("热油"); } // 到蔬菜 public abstract void pourVegetable(); // 到调味品 public abstract void pourSauce(); // 翻炒 public void fly() { System.out.println("翻炒...."); } }
具体子类
package com.jsxs.behavioralModel.template; /** * @Author Jsxs * @Date 2023/4/22 20:44 * @PackageName:com.jsxs.behavioralModel.template * @ClassName: Baicai * @Description: TODO 具体子类 * @Version 1.0 */ public class Baicai extends AbstractClass{ @Override public void pourVegetable() { System.out.println("白菜"); } @Override public void pourSauce() { System.out.println("醋和垃圾"); } }
package com.jsxs.behavioralModel.template; /** * @Author Jsxs * @Date 2023/4/22 20:45 * @PackageName:com.jsxs.behavioralModel.template * @ClassName: Baocai * @Description: TODO 具体子类 * @Version 1.0 */ public class Baocai extends AbstractClass{ @Override public void pourVegetable() { System.out.println("包菜"); } @Override public void pourSauce() { System.out.println("蒜蓉"); } }
测试
package com.jsxs.behavioralModel.template; /** * @Author Jsxs * @Date 2023/4/22 20:46 * @PackageName:com.jsxs.behavioralModel.template * @ClassName: Client * @Description: TODO * @Version 1.0 */ public class Client { public static void main(String[] args) { Baocai baocai = new Baocai(); baocai.cookProcess(); } }
(4).优缺点
优点:
提高代码复用性
: 将相同部分的代码放在抽象的父类中,而将不同的代码放入不同的子类中。实现了反向控制
: 通过一个父类调用其子类的操作,通过对子类的具体实现扩展不同的行为,实现了方向控制,并符合"开闭原则";
缺点:
- 对每一个不同的实现都需要定义一个子类,这会导致
类的个数增加
,系统更加庞大,设计也更加抽象。 - 父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向的控制结果,
它提高了代码阅读的难度
。
(4).使用场景
- 算法的整体步骤很固定,但其中个别部分容易变化的时候,这时候可以使用模板方法模式,将容易变得部分抽象出来,供子类实现。
- 需要通过子类来决定父类算法中某个步骤是否执行,实现子类对父类得反向控制。
(6).JDK源码分析
InputStream类就是用了模板方法模式,在InputStream类中定义了多个Read()方法。重载…
2.策略模式
(1).概述
我们出去旅游可供选择的方式有很多种,可以骑自行车、可以坐汽车、可以坐火车。
作为一个程序员,开发需要选择一款开发工具,当然可以使用Idea进行代码开发,也可以使用Eclips。
定义: 该模式定义了一些列算法,并将每个算法都封装起来。使他们可以相互替换,且算法的变化并不会影响使用算法的客户(都会达到目的地)
,策略模式属于对象行为模式,它通过对算法进行描述,把使用算法的责任
和算法的实现分割开
来,并委派给不同的对象对这些算法进行管理。
(2).结构
- 抽象策略类: 这是一个抽象角色,通常由一个
接口或抽象类
实现。此角色给出所有的具体策略类所需的接口。 - 具体策略类:
实现了抽象策略定义的接口
,提供具体的算法实现或行为。 - 环境类: 持有一个
策略类的引用
,最终给客户端调用。
(3).案列实现
eg: 促销活动
一家百货公司在顶年度的促销活动,针对不同的节日(春节、中秋节、圣诞节)退出不同的活动,由促销员将不同的活动展示给客户。
抽象策略
package com.jsxs.behavioralModel.strategy; /** * @Author Jsxs * @Date 2023/4/23 9:05 * @PackageName:com.jsxs.behavioralModel.strategy * @ClassName: Strategy * @Description: TODO 抽象策略类 * @Version 1.0 */ public interface Strategy { void show(); }
具体策略
package com.jsxs.behavioralModel.strategy; /** * @Author Jsxs * @Date 2023/4/23 9:07 * @PackageName:com.jsxs.behavioralModel.strategy * @ClassName: StrategyImlA * @Description: TODO 具体策略类 * @Version 1.0 */ public class StrategyImlA implements Strategy{ @Override public void show() { System.out.println("A"); } }
package com.jsxs.behavioralModel.strategy; /** * @Author Jsxs * @Date 2023/4/23 9:07 * @PackageName:com.jsxs.behavioralModel.strategy * @ClassName: StrategyImlB * @Description: TODO * @Version 1.0 */ public class StrategyImlB implements Strategy{ @Override public void show() { System.out.println("B"); } }
package com.jsxs.behavioralModel.strategy; /** * @Author Jsxs * @Date 2023/4/23 9:08 * @PackageName:com.jsxs.behavioralModel.strategy * @ClassName: StrategyImlC * @Description: TODO * @Version 1.0 */ public class StrategyImlC implements Strategy{ @Override public void show() { System.out.println("C"); } }
环境类
package com.jsxs.behavioralModel.strategy; /** * @Author Jsxs * @Date 2023/4/23 9:10 * @PackageName:com.jsxs.behavioralModel.strategy * @ClassName: ContextEnv * @Description: TODO 环境类: 销售员 * @Version 1.0 */ public class ContextEnv { // 聚合 private Strategy strategy; // 有参构造赋值 public ContextEnv(Strategy strategy) { this.strategy = strategy; } // 促销活动展示出来 public void salesShow(){ strategy.show(); } public Strategy getStrategy() { return strategy; } public void setStrategy(Strategy strategy) { this.strategy = strategy; } }
package com.jsxs.behavioralModel.strategy; /** * @Author Jsxs * @Date 2023/4/23 9:13 * @PackageName:com.jsxs.behavioralModel.strategy * @ClassName: Client * @Description: TODO * @Version 1.0 */ public class Client { public static void main(String[] args) { ContextEnv contextEnv = new ContextEnv(new StrategyImlA()); contextEnv.salesShow(); // ----- 复用这个对象 contextEnv.setStrategy(new StrategyImlB()); contextEnv.salesShow(); } }