行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。
行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。

一.模板方法模式

定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。
结构
模板方法(Template Method)模式包含以下主要角色:
抽象类(Abstract Class):负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成。
模板方法:定义了算法的骨架,按某种顺序调用其包含的基本方法。
基本方法:是实现算法各个步骤的方法,是模板方法的组成部分。基本方法又可以分为三种:
抽象方法(Abstract Method) :一个抽象方法由抽象类声明、由其具体子类实现。
具体方法(Concrete Method) :一个具体方法由一个抽象类或具体类声明并实现,其子类可以进行覆盖也可以直接继承。
钩子方法(Hook Method) :在抽象类中已经实现,包括用于判断的逻辑方法和需要子类重写的空方法两种。一般钩子方法是用于判断的逻辑方法,这类方法名一般为isXxx,返回值类型为boolean类型。
具体子类(Concrete Class):实现抽象类中所定义的抽象方法和钩子方法,它们是一个顶级逻辑的组成步骤。
image.png

  1. //模板类
  2. public abstract class AbsClass {
  3. //定义模板方法
  4. public final void cookProcess() {
  5. //第一步:倒油
  6. this.pourOil();
  7. //第二步:热油
  8. this.heatOil();
  9. //第三步:倒蔬菜
  10. this.pourVegetable();
  11. //第四步:倒调味料
  12. this.pourSauce();
  13. //第五步:翻炒
  14. this.fry();
  15. }
  16. public void pourOil() {
  17. System.out.println("倒油");
  18. }
  19. //第二步:热油是一样的,
  20. public void heatOil() {
  21. System.out.println("热油");
  22. }
  23. //第三步:倒蔬菜是不一样的(一个下包菜,一个是下菜心)
  24. public abstract void pourVegetable();
  25. //第四步:倒调味料是不一样
  26. public abstract void pourSauce();
  27. //第五步:翻炒是一样的,
  28. public void fry(){
  29. System.out.println("炒啊炒啊炒到熟啊");
  30. }
  31. }
  1. 具体实现类
  2. public class cookImpl extends AbsClass{
  3. public void pourVegetable() {
  4. System.out.println("放蔬菜");
  5. }
  6. public void pourSauce() {
  7. System.out.println("放调料");
  8. }
  9. }

二.策略模式

该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。
结构
策略模式的主要角色如下:

  • 抽象策略(Strategy)类:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
  • 具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现或行为。
  • 环境(Context)类:持有一个策略类的引用,最终给客户端调用。

image.png

  1. //抽象的策略接口
  2. public interface strategy {
  3. public void show();
  4. }
  1. //俩个具体的策略
  2. public class strategyA implements strategy{
  3. public void show() {
  4. System.out.println("买一送一");
  5. }
  6. }
  7. public class strategyB implements strategy{
  8. public void show() {
  9. System.out.println("打八折");
  10. }
  11. }
  1. //策略执行者
  2. public class SaleMan {
  3. private strategy strategy;
  4. public SaleMan(strategy strategy) {
  5. this.strategy = strategy;
  6. }
  7. public void saleManShow(){
  8. this.strategy.show();
  9. }
  10. }

三.命令模式

将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。这样两者之间通过命令对象进行沟通,这样方便将命令对象进行存储、传递、调用、增加与管理。
结构
命令模式包含以下主要角色:
抽象命令类(Command)角色: 定义命令的接口,声明执行的方法。
具体命令(Concrete Command)角色:具体的命令,实现命令接口;通常会持有接收者,并调用接收者的功能来完成命令要执行的操作。
实现者/接收者(Receiver)角色: 接收者,真正执行命令的对象。任何类都可能成为一个接收者,只要它能够实现命令要求实现的相应功能。
调用者/请求者(Invoker)角色: 要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。
image.png

  1. public interface Command {
  2. void execute();//只需要定义一个统一的执行方法
  3. }
  4. public class OrderCommand implements Command {
  5. //持有接受者对象
  6. private SeniorChef receiver;
  7. private Order order;
  8. public OrderCommand(SeniorChef receiver, Order order){
  9. this.receiver = receiver;
  10. this.order = order;
  11. }
  12. public void execute() {
  13. System.out.println(order.getDiningTable() + "桌的订单:");
  14. Set<String> keys = order.getFoodDic().keySet();
  15. for (String key : keys) {
  16. receiver.makeFood(order.getFoodDic().get(key),key);
  17. }
  18. try {
  19. Thread.sleep(100);//停顿一下 模拟做饭的过程
  20. } catch (InterruptedException e) {
  21. e.printStackTrace();
  22. }
  23. System.out.println(order.getDiningTable() + "桌的饭弄好了");
  24. }
  25. }
  26. public class Order {
  27. // 餐桌号码
  28. private int diningTable;
  29. // 用来存储餐名并记录份数
  30. private Map<String, Integer> foodDic = new HashMap<String, Integer>();
  31. public int getDiningTable() {
  32. return diningTable;
  33. }
  34. public void setDiningTable(int diningTable) {
  35. this.diningTable = diningTable;
  36. }
  37. public Map<String, Integer> getFoodDic() {
  38. return foodDic;
  39. }
  40. public void setFoodDic(String name, int num) {
  41. foodDic.put(name,num);
  42. }
  43. }
  44. // 资深大厨类 是命令的Receiver
  45. public class SeniorChef {
  46. public void makeFood(int num,String foodName) {
  47. System.out.println(num + "份" + foodName);
  48. }
  49. }
  50. public class Waitor {
  51. private ArrayList<Command> commands;//可以持有很多的命令对象
  52. public Waitor() {
  53. commands = new ArrayList();
  54. }
  55. public void setCommand(Command cmd){
  56. commands.add(cmd);
  57. }
  58. // 发出命令 喊 订单来了,厨师开始执行
  59. public void orderUp() {
  60. System.out.println("美女服务员:叮咚,大厨,新订单来了.......");
  61. for (int i = 0; i < commands.size(); i++) {
  62. Command cmd = commands.get(i);
  63. if (cmd != null) {
  64. cmd.execute();
  65. }
  66. }
  67. }
  68. }
  69. public class Client {
  70. public static void main(String[] args) {
  71. //创建2个order
  72. Order order1 = new Order();
  73. order1.setDiningTable(1);
  74. order1.getFoodDic().put("西红柿鸡蛋面",1);
  75. order1.getFoodDic().put("小杯可乐",2);
  76. Order order2 = new Order();
  77. order2.setDiningTable(3);
  78. order2.getFoodDic().put("尖椒肉丝盖饭",1);
  79. order2.getFoodDic().put("小杯雪碧",1);
  80. //创建接收者
  81. SeniorChef receiver=new SeniorChef();
  82. //将订单和接收者封装成命令对象
  83. OrderCommand cmd1 = new OrderCommand(receiver, order1);
  84. OrderCommand cmd2 = new OrderCommand(receiver, order2);
  85. //创建调用者 waitor
  86. Waitor invoker = new Waitor();
  87. invoker.setCommand(cmd1);
  88. invoker.setCommand(cmd2);
  89. //将订单带到柜台 并向厨师喊 订单来了
  90. invoker.orderUp();
  91. }
  92. }

四.责任链模式

又名职责链模式,为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。
结构
职责链模式主要包含以下角色:
抽象处理者(Handler)角色:定义一个处理请求的接口,包含抽象处理方法和一个后继连接。
具体处理者(Concrete Handler)角色:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
客户类(Client)角色:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。
image.png

  1. public class LeaveRequest {
  2. private String name;
  3. private Integer day;
  4. public LeaveRequest(String name, Integer day) {
  5. this.name = name;
  6. this.day = day;
  7. }
  8. public String getName() {
  9. return name;
  10. }
  11. public Integer getDay() {
  12. return day;
  13. }
  14. }
  1. //抽象处理者
  2. public abstract class Handler {
  3. protected static final int NUM_ONE=1;
  4. protected static final int NUM_THREE=3;
  5. protected static final int NUM_SEVEN=7;
  6. private int start;
  7. private int end;
  8. //声明后继者
  9. Handler next;
  10. public Handler(int start, int end) {
  11. this.start = start;
  12. this.end = end;
  13. }
  14. public void setNext(Handler next) {
  15. this.next = next;
  16. }
  17. public abstract void handlerLeave(LeaveRequest leave);
  18. public final void submit(LeaveRequest leave){
  19. this.handlerLeave(leave);
  20. if(this.next !=null && leave.getDay()>this.end){
  21. this.next.submit(leave);
  22. }else {
  23. System.out.println("流程完毕");
  24. }
  25. }
  26. }

具体处理者继承抽象处理者并声明next

五.状态模式

对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。
结构
状态模式包含以下主要角色。
环境(Context)角色:也称为上下文,它定义了客户程序需要的接口,维护一个当前状态,并将与状态相关的操作委托给当前状态对象来处理。
抽象状态(State)角色:定义一个接口,用以封装环境对象中的特定状态所对应的行为。
具体状态(Concrete State)角色:实现抽象状态所对应的行为。
image.png

  1. //抽象状态类
  2. public abstract class LiftState {
  3. //定义一个环境角色,也就是封装状态的变化引起的功能变化
  4. protected Context context;
  5. public void setContext(Context context) {
  6. this.context = context;
  7. }
  8. //电梯开门动作
  9. public abstract void open();
  10. //电梯关门动作
  11. public abstract void close();
  12. //电梯运行动作
  13. public abstract void run();
  14. //电梯停止动作
  15. public abstract void stop();
  16. }
  17. //开启状态
  18. public class OpenningState extends LiftState {
  19. //开启当然可以关闭了,我就想测试一下电梯门开关功能
  20. @Override
  21. public void open() {
  22. System.out.println("电梯门开启...");
  23. }
  24. @Override
  25. public void close() {
  26. //状态修改
  27. super.context.setLiftState(Context.closeingState);
  28. //动作委托为CloseState来执行,也就是委托给了ClosingState子类执行这个动作
  29. super.context.getLiftState().close();
  30. }
  31. //电梯门不能开着就跑,这里什么也不做
  32. @Override
  33. public void run() {
  34. //do nothing
  35. }
  36. //开门状态已经是停止的了
  37. @Override
  38. public void stop() {
  39. //do nothing
  40. }
  41. }
  42. //运行状态
  43. public class RunningState extends LiftState {
  44. //运行的时候开电梯门?你疯了!电梯不会给你开的
  45. @Override
  46. public void open() {
  47. //do nothing
  48. }
  49. //电梯门关闭?这是肯定了
  50. @Override
  51. public void close() {//虽然可以关门,但这个动作不归我执行
  52. //do nothing
  53. }
  54. //这是在运行状态下要实现的方法
  55. @Override
  56. public void run() {
  57. System.out.println("电梯正在运行...");
  58. }
  59. //这个事绝对是合理的,光运行不停止还有谁敢做这个电梯?!估计只有上帝了
  60. @Override
  61. public void stop() {
  62. super.context.setLiftState(Context.stoppingState);
  63. super.context.stop();
  64. }
  65. }
  66. //停止状态
  67. public class StoppingState extends LiftState {
  68. //停止状态,开门,那是要的!
  69. @Override
  70. public void open() {
  71. //状态修改
  72. super.context.setLiftState(Context.openningState);
  73. //动作委托为CloseState来执行,也就是委托给了ClosingState子类执行这个动作
  74. super.context.getLiftState().open();
  75. }
  76. @Override
  77. public void close() {//虽然可以关门,但这个动作不归我执行
  78. //状态修改
  79. super.context.setLiftState(Context.closeingState);
  80. //动作委托为CloseState来执行,也就是委托给了ClosingState子类执行这个动作
  81. super.context.getLiftState().close();
  82. }
  83. //停止状态再跑起来,正常的很
  84. @Override
  85. public void run() {
  86. //状态修改
  87. super.context.setLiftState(Context.runningState);
  88. //动作委托为CloseState来执行,也就是委托给了ClosingState子类执行这个动作
  89. super.context.getLiftState().run();
  90. }
  91. //停止状态是怎么发生的呢?当然是停止方法执行了
  92. @Override
  93. public void stop() {
  94. System.out.println("电梯停止了...");
  95. }
  96. }
  97. //关闭状态
  98. public class ClosingState extends LiftState {
  99. @Override
  100. //电梯门关闭,这是关闭状态要实现的动作
  101. public void close() {
  102. System.out.println("电梯门关闭...");
  103. }
  104. //电梯门关了再打开,逗你玩呢,那这个允许呀
  105. @Override
  106. public void open() {
  107. super.context.setLiftState(Context.openningState);
  108. super.context.open();
  109. }
  110. //电梯门关了就跑,这是再正常不过了
  111. @Override
  112. public void run() {
  113. super.context.setLiftState(Context.runningState);
  114. super.context.run();
  115. }
  116. //电梯门关着,我就不按楼层
  117. @Override
  118. public void stop() {
  119. super.context.setLiftState(Context.stoppingState);
  120. super.context.stop();
  121. }
  122. }
  123. //环境角色
  124. public class Context {
  125. //定义出所有的电梯状态
  126. public final static OpenningState openningState = new OpenningState();//开门状态,这时候电梯只能关闭
  127. public final static ClosingState closeingState = new ClosingState();//关闭状态,这时候电梯可以运行、停止和开门
  128. public final static RunningState runningState = new RunningState();//运行状态,这时候电梯只能停止
  129. public final static StoppingState stoppingState = new StoppingState();//停止状态,这时候电梯可以开门、运行
  130. //定义一个当前电梯状态
  131. private LiftState liftState;
  132. public LiftState getLiftState() {
  133. return this.liftState;
  134. }
  135. public void setLiftState(LiftState liftState) {
  136. //当前环境改变
  137. this.liftState = liftState;
  138. //把当前的环境通知到各个实现类中
  139. this.liftState.setContext(this);
  140. }
  141. public void open() {
  142. this.liftState.open();
  143. }
  144. public void close() {
  145. this.liftState.close();
  146. }
  147. public void run() {
  148. this.liftState.run();
  149. }
  150. public void stop() {
  151. this.liftState.stop();
  152. }
  153. }
  154. //测试类
  155. public class Client {
  156. public static void main(String[] args) {
  157. Context context = new Context();
  158. context.setLiftState(new ClosingState());
  159. context.open();
  160. context.close();
  161. context.run();
  162. context.stop();
  163. }
  164. }

六.观察者模式

又被称为发布-订阅(Publish/Subscribe)模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己
结构
在观察者模式中有如下角色:
Subject:抽象主题(抽象被观察者),抽象主题角色把所有观察者对象保存在一个集合里,每个主题都可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察者对象。
ConcreteSubject:具体主题(具体被观察者),该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知。
Observer:抽象观察者,是观察者的抽象类,它定义了一个更新接口,使得在得到主题更改通知时更新自己。
ConcrereObserver:具体观察者,实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态
image.png

  1. //观察者接口
  2. public interface Observer {
  3. //要更新的内容
  4. public void update(String str);
  5. }
  1. public interface Subject {
  2. //声明 添加观察者
  3. public void attach(Observer obs);
  4. //删除观察者
  5. public void detach(Observer obs);
  6. //发布消息
  7. public void notify(String str);
  8. }
  1. public class SubscriptionSubject implements Subject{
  2. //集合存放观察者对象
  3. ArrayList<Observer> list =new ArrayList<Observer>();
  4. public void attach(Observer obs) {
  5. list.add(obs);
  6. }
  7. public void detach(Observer obs) {
  8. list.remove(obs);
  9. }
  10. public void notify(String str) {
  11. //遍历list 更新消息
  12. for (Observer observer : list) {
  13. observer.update(str);
  14. }
  15. }
  16. }

七.中介者模式

又叫调停模式,定义一个中介角色来封装一系列对象之间的交互,使原有对象之间的耦合松散,且可以独立地改变它们之间的交互。
image.png
结构
中介者模式包含以下主要角色:
抽象中介者(Mediator)角色:它是中介者的接口,提供了同事对象注册与转发同事对象信息的抽象方法。
具体中介者(ConcreteMediator)角色:实现中介者接口,定义一个 List 来管理同事对象,协调各个同事角色之间的交互关系,因此它依赖于同事角色。
抽象同事类(Colleague)角色:定义同事类的接口,保存中介者对象,提供同事对象交互的抽象方法,实现所有相互影响的同事类的公共功能。
具体同事类(Concrete Colleague)角色:是抽象同事类的实现者,当需要与其他同事对象交互时,由中介者对象负责后续的交互。
image.png

  1. //抽象中介者
  2. public abstract class Mediator {
  3. //申明一个联络方法
  4. public abstract void constact(String message,Person person);
  5. }
  6. //抽象同事类
  7. public abstract class Person {
  8. protected String name;
  9. protected Mediator mediator;
  10. public Person(String name,Mediator mediator){
  11. this.name = name;
  12. this.mediator = mediator;
  13. }
  14. }
  15. //具体同事类 房屋拥有者
  16. public class HouseOwner extends Person {
  17. public HouseOwner(String name, Mediator mediator) {
  18. super(name, mediator);
  19. }
  20. //与中介者联系
  21. public void constact(String message){
  22. mediator.constact(message, this);
  23. }
  24. //获取信息
  25. public void getMessage(String message){
  26. System.out.println("房主" + name +"获取到的信息:" + message);
  27. }
  28. }
  29. //具体同事类 承租人
  30. public class Tenant extends Person {
  31. public Tenant(String name, Mediator mediator) {
  32. super(name, mediator);
  33. }
  34. //与中介者联系
  35. public void constact(String message){
  36. mediator.constact(message, this);
  37. }
  38. //获取信息
  39. public void getMessage(String message){
  40. System.out.println("租房者" + name +"获取到的信息:" + message);
  41. }
  42. }
  43. //中介机构
  44. public class MediatorStructure extends Mediator {
  45. //首先中介结构必须知道所有房主和租房者的信息
  46. private HouseOwner houseOwner;
  47. private Tenant tenant;
  48. public HouseOwner getHouseOwner() {
  49. return houseOwner;
  50. }
  51. public void setHouseOwner(HouseOwner houseOwner) {
  52. this.houseOwner = houseOwner;
  53. }
  54. public Tenant getTenant() {
  55. return tenant;
  56. }
  57. public void setTenant(Tenant tenant) {
  58. this.tenant = tenant;
  59. }
  60. public void constact(String message, Person person) {
  61. if (person == houseOwner) { //如果是房主,则租房者获得信息
  62. tenant.getMessage(message);
  63. } else { //反正则是房主获得信息
  64. houseOwner.getMessage(message);
  65. }
  66. }
  67. }
  68. //测试类
  69. public class Client {
  70. public static void main(String[] args) {
  71. //一个房主、一个租房者、一个中介机构
  72. MediatorStructure mediator = new MediatorStructure();
  73. //房主和租房者只需要知道中介机构即可
  74. HouseOwner houseOwner = new HouseOwner("张三", mediator);
  75. Tenant tenant = new Tenant("李四", mediator);
  76. //中介结构要知道房主和租房者
  77. mediator.setHouseOwner(houseOwner);
  78. mediator.setTenant(tenant);
  79. tenant.constact("需要租三室的房子");
  80. houseOwner.constact("我这有三室的房子,你需要租吗?");
  81. }
  82. }

八.迭代器模式

提供一个对象来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示
结构
迭代器模式主要包含以下角色:
抽象聚合(Aggregate)角色:定义存储、添加、删除聚合元素以及创建迭代器对象的接口。
具体聚合(ConcreteAggregate)角色:实现抽象聚合类,返回一个具体迭代器的实例。
抽象迭代器(Iterator)角色:定义访问和遍历聚合元素的接口,通常包含 hasNext()、next() 等方法。
具体迭代器(Concretelterator)角色:实现抽象迭代器接口中所定义的方法,完成对聚合对象的遍历,记录遍历的当前位置。

定义迭代器接口,声明hasNext、next方法

  1. public interface StudentIterator {
  2. boolean hasNext();
  3. Student next();
  4. }
  1. 定义具体的迭代器类,重写所有的抽象方法
public class StudentIteratorImpl implements StudentIterator {
    private List<Student> list;
    private int position = 0;

    public StudentIteratorImpl(List<Student> list) {
        this.list = list;
    }

    @Override
    public boolean hasNext() {
        return position < list.size();
    }

    @Override
    public Student next() {
        Student currentStudent = list.get(position);
        position ++;
        return currentStudent;
    }
}

定义抽象容器类,包含添加元素,删除元素,获取迭代器对象的方法

public interface StudentAggregate {
    void addStudent(Student student);

    void removeStudent(Student student);

    StudentIterator getStudentIterator();
}

定义具体的容器类,重写所有的方法

public class StudentAggregateImpl implements StudentAggregate {

    private List<Student> list = new ArrayList<Student>();  // 学生列表

    @Override
    public void addStudent(Student student) {
        this.list.add(student);
    }

    @Override
    public void removeStudent(Student student) {
        this.list.remove(student);
    }

    @Override
    public StudentIterator getStudentIterator() {
        return new StudentIteratorImpl(list);
    }
}

九.访问者模式

封装一些作用于某种数据结构中的各元素的操作,它可以在不改变这个数据结构的前提下定义作用于这些元素的新的操作。