资讯专栏INFORMATION COLUMN

设计模式之行为型

hlcc / 3272人阅读

摘要:设计模式分创建型模式,结构型模式和行为型模式。责任链模式使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。状态模式的核心是封装,通过状态的变更引起行为的变更。

前言

最近加班是真的很多,无法腾出大块时间来学习。设计模式又不想只更到一半半途而废,想了又想,决定精简,保证大家一看就懂(看完就忘...)。设计模式分创建型模式,结构型模式和行为型模式。到目前为止,创建型模式已经讲完,对于剩下的模式,会分成这两大块统一讲解。

行为型模式

行为型模式主要关注的点事类的动作,各个类之间相互的作用,将职责划分清楚,使我们的代码更加的清晰。

策略模式

</>复制代码

  1. 定义一组算法,将每个算法都封装起来,并且使他们之间可以互换。

</>复制代码

  1. 策略模式是一个出现频率很高,但又很简单的模式。下面的场景是我们要出去旅游,但是可以选择出去旅游的交通方式,比如坐飞机,坐火车或者步行。废话不再多说,直接上码:

</>复制代码

  1. public interface Strategy {
  2. void travel();
  3. }

</>复制代码

  1. public class Walk implements Strategy {
  2. @Override
  3. public void travel() {
  4. System.out.println("步行去旅行");
  5. }
  6. }

</>复制代码

  1. public class Train implements Strategy {
  2. @Override
  3. public void travel() {
  4. System.out.println("坐火车去旅行");
  5. }
  6. }

</>复制代码

  1. public class Airplane implements Strategy {
  2. @Override
  3. public void travel() {
  4. System.out.println("坐着飞机去旅行");
  5. }
  6. }

</>复制代码

  1. public class Context {
  2. private Strategy strategy;
  3. public Context(Strategy strategy) {
  4. this.strategy = strategy;
  5. }
  6. public void execute(){
  7. strategy.travel();
  8. }
  9. }

</>复制代码

  1. public class Client {
  2. public static void main(String[] args) {
  3. Context context = new Context(new Airplane());
  4. context.execute();
  5. }
  6. }
  7. console
  8. 坐着飞机去旅行

策略模式的优点非常明显,在现有的系统中增加一个策略太容易,只要实现接口就可以了,其他都不用修改,类似于一个可以反复拆卸的插件,符合ocp原则。其缺点就是每个策略都是一个类,复用性很小,复杂的业务场景容易发生类数量爆炸,并且策略模式和迪米特法则是违背的,我们看下上面的clent场景类(相当于项目中的高层调用模块),我只是想使用一个策略,凭什么就要了解这个策略呢?那要封装类就没有意义了,这是策略模式的一个大缺点,所以策略模式很少多带带出现,大多结合其他模式来弥补这个缺陷,如工厂方法或者代理模式。

观察者模式

</>复制代码

  1. 定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新

策略模式也叫发布订阅模式,其中最主要额角色名称就是subject被观察者和observer观察者。接下来会模拟一个场景,学校作为被观察者发布放假的消息,家长和学生作为观察者实现自己的逻辑:

</>复制代码

  1. /**
  2. * 主题(被观察者)需要实现的职责,就是可以动态的增加删除观察者。
  3. * 根据主题的状态通知所有的观察者Observer
  4. */
  5. public abstract class Subject {
  6. private Vector observerList = new Vector<>();
  7. private int status;
  8. public void addObserver(Observer observer){
  9. observerList.add(observer);
  10. }
  11. public void delObserver(Observer observer){
  12. observerList.remove(observer);
  13. }
  14. public void notifyAllObserver(){
  15. observerList.forEach(observer -> {
  16. observer.update();
  17. });
  18. }
  19. }

</>复制代码

  1. public class SchoolSubject extends Subject {
  2. //学校宣布放七天假期
  3. public void haveSevenDaysHoliday(){
  4. System.out.println("学校:从今天开始放假,所有学生七天后返校");
  5. super.notifyAllObserver();
  6. }
  7. }

</>复制代码

  1. public interface Observer {
  2. //观察者,被通知了实现其自己的逻辑
  3. void update() ;
  4. }

</>复制代码

  1. public class Parent implements Observer {
  2. @Override
  3. public void update() {
  4. System.out.println("家长:这倒霉孩子怎么又放假了,坚决不能让他玩王者荣耀....");
  5. }
  6. }

</>复制代码

  1. public class Student implements Observer {
  2. @Override
  3. public void update() {
  4. System.out.println("学生:哇哈哈,终于有时间打王者荣耀喽");
  5. }
  6. }

</>复制代码

  1. public class Client {
  2. public static void main(String[] args) {
  3. SchoolSubject subject = new SchoolSubject();
  4. Student student = new Student();
  5. Parent parent = new Parent();
  6. subject.addObserver(student);
  7. subject.addObserver(parent);
  8. subject.haveSevenDaysHoliday();
  9. }
  10. }
  11. console
  12. 学校:从今天开始放假,所有学生七天后返校
  13. 学生:哇哈哈,终于有时间打王者荣耀喽
  14. 家长:这倒霉孩子怎么又放假了,坚决不能让他玩王者荣耀....

虽说观察者和被观察者是耦合在一起的,但是不管是扩展增加观察者还是被观察者都非常容易。并且根据单一职责原则,每个类的职责都是唯一,需要一套机制将类串联起来形成一个真实的场景,就比如学校公布放假,孩子想着玩游戏,家长为了孩子的成绩禁止孩子玩游戏,然后因为学校放假我就不玩了(小学生,你懂得),这样就形成了一个触发机制。其缺点就是执行效率低下,需异步执行。从原理上看,我们常用的mq就是观察者模式的升级版。

责任链模式

</>复制代码

  1. 使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。

责任链我们很容易想到链表结构,实际上责任链就是一种基于链表的处理方式。当一个请求过来,调用链表的头结点,处理之后再往后流转。
有这么一个场景:路飞饿了打开美团准备订外卖。选中吃的后,进行下单,首先校验是否在营业时间内,然后校验是否在配送范围内,然后校验是否有货等等,设定责任链都通过后,路飞才能订到饭。

</>复制代码

  1. //链表内结点的基类
  2. public abstract class RuleHandler {
  3. protected RuleHandler successor;
  4. public abstract void echo(Context context);
  5. public void setSuccessor(RuleHandler successor) {
  6. this.successor = successor;
  7. }
  8. public RuleHandler getSuccessor() {
  9. return successor;
  10. }
  11. }

</>复制代码

  1. //判断营业时间
  2. public class TimeHandler extends RuleHandler {
  3. @Override
  4. public void echo(Context context) {
  5. //营业时间判断
  6. if (context.isTimeInRange()){
  7. if (this.getSuccessor()!=null){
  8. this.getSuccessor().echo(context);
  9. }
  10. }else {
  11. throw new RuntimeException("不在营业时间内");
  12. }
  13. }
  14. }

</>复制代码

  1. //判断是否在配送范围内
  2. public class AreaHanler extends RuleHandler {
  3. @Override
  4. public void echo(Context context) {
  5. if (context.isAreaInRange()){
  6. if (this.getSuccessor()!=null){
  7. this.getSuccessor().echo(context);
  8. }
  9. }else {
  10. throw new RuntimeException("不在配送范围内");
  11. }
  12. }
  13. }

</>复制代码

  1. //判断库存
  2. public class StockHandler extends RuleHandler {
  3. @Override
  4. public void echo(Context context) {
  5. if (context.hasStock()){
  6. if (this.getSuccessor()!=null){
  7. this.getSuccessor().echo(context);
  8. }
  9. }else {
  10. throw new RuntimeException("挑选的商品已经卖完");
  11. }
  12. }
  13. }

客户端调用逻辑:

</>复制代码

  1. public class Client {
  2. public static void main(String[] args) {
  3. RuleHandler timeHandler = new TimeHandler();
  4. RuleHandler areaHandler = new AreaHanler();
  5. RuleHandler stockHandler = new StockHandler();
  6. timeHandler.setSuccessor(areaHandler);
  7. areaHandler.setSuccessor(stockHandler);
  8. timeHandler.echo(new Context());
  9. }
  10. }

代码非常简单,责任链模式的重点是在链上,由一条链去处理请求并返回相应的结果。它非常显著的优点就是将请求和处理分开,两者解耦,提高系统的灵活性。缺点就是链表遍历必须从链头到链尾,存在性能问题。采用了类似递归调用的方式,增大了读懂逻辑的难度

模板方法模式

在之前的博客里已经长篇大论过,故直接拿过来。
模板方法

状态模式

</>复制代码

  1. 当一个对象内在状态改变时允许其改变行为,这个对象看起来像改变了其类。

状态模式的核心是封装,通过状态的变更引起行为的变更。现在大家来思考一下,电脑有三种状态,分别为关机,已启动。

</>复制代码

  1. //代表环境,也就是状态的主体
  2. public class Context {
  3. //所有的电脑状态
  4. public final static OpenState OPEN = new OpenState();
  5. public final static CloseState CLOSE = new CloseState();
  6. //电脑当前的状态
  7. private ComputerState currentState;
  8. public ComputerState getCurrentState() {
  9. return currentState;
  10. }
  11. public void setCurrentState(ComputerState currentState) {
  12. this.currentState = currentState;
  13. this.currentState.setContext(this);
  14. }
  15. public void openMachine() {
  16. this.currentState.openMachine();
  17. }
  18. public void closeMachine() {
  19. this.currentState.closeMachine();
  20. }
  21. }

</>复制代码

  1. //状态基类,真实的电脑逻辑封装在了状态中
  2. public abstract class ComputerState {
  3. protected Context context;
  4. public void setContext(Context context) {
  5. this.context = context;
  6. }
  7. public abstract void openMachine();
  8. public abstract void closeMachine();
  9. }

</>复制代码

  1. public class OpenState extends ComputerState{
  2. @Override
  3. public void openMachine() {
  4. System.out.println("电脑开机...");
  5. }
  6. @Override
  7. public void closeMachine() {
  8. super.context.setCurrentState(Context.CLOSE);
  9. super.context.getCurrentState().closeMachine();
  10. }
  11. }

</>复制代码

  1. public class CloseState extends ComputerState {
  2. @Override
  3. public void openMachine() {
  4. super.context.setCurrentState(Context.OPEN);
  5. super.context.getCurrentState().openMachine();
  6. }
  7. @Override
  8. public void closeMachine() {
  9. System.out.println("电脑关机...");
  10. }
  11. }

客户端测试类:

</>复制代码

  1. public class Client {
  2. public static void main(String[] args) {
  3. Context context = new Context();
  4. context.setCurrentState(Context.OPEN);
  5. context.openMachine();
  6. context.closeMachine();
  7. }
  8. }

状态模式的优点有结构清晰,避免了各种条件的判断,省掉了swtich...case,if...else语句的使用,提升了代码的可读性。遵循了单一职责原则和开闭原则,每个状态都是一个子类,增加状态只需增加一个状态子类,修改状态,修改对应的子类就可以了。封装性非常好,客户端不需知道内部状态的转换以及相应的逻辑.其缺点就是状态子类会太多,并且我们可以将状态存储到数据库中,然后根据状态执行相应的操作,这也是一种不错的实现方式,具体如何使用看大家个人喜好了。

总结

本章的行为型模式总结了策略模式、观察者模式、责任链模式、模板方法模式和状态模式,其实不仅于此,还有备忘录模式和命令模式等,但因其使用场景有限,就不做一一探讨了,留给读者自己学习~.~

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/68293.html

相关文章

  • PHP基础

    摘要:分别为适配器模式,装饰器模式,代理模式,外观模式,桥接模式,组合模式,享元模式。设计模式五适配器模式适配器模式将某个对象的接生成器和协程的实现在这篇文章中,作者针对那些比较难以理解的概念,以一个更为通俗的方式去讲明白。。 PHP 源码注解 PHP 的详细源码注解 PHP 字符串操作整理 一些有关字符串的常用操作。 Redis 常见七种使用场景 (PHP 实战) 这篇文章主要介绍利用 R...

    HtmlCssJs 评论0 收藏0
  • 忘了再看设计模式-行为

    摘要:推文用设计模式解构三国是一种什么体验行为型设计模式一策略模式工厂模式优化结构状态模式随着状态改变而改变行为。推文状态机与状态模式责任链模式多个对象依次处理请求前者指定后者。代理模式代理针对一个对象,为了增加控制等中介双方都是多个,为了解耦。 策略模式 选择使用封装好的一系列算法,可相互替换。 类比:商店[Context]买完衣服买单[Stratege](现金[Concrete Stra...

    ShevaKuilin 评论0 收藏0
  • 设计模式策略模式

    摘要:在策略模式中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。而本次示例使用策略模式来实现这种数学运算。 在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。其实现原理是定义一系列的算法,将他们一个个封装起来,并且是他们可以互相替换,这样避免了使用 if … else 语句所带来的复杂度和维护...

    104828720 评论0 收藏0
  • Java设计模式概述

    摘要:设计模式的类别设计模式一共分为种类型,共种。属于结构型的设计模式适配器模式桥接模式装饰模式组合模式外观模式享元模式代理模式。问题描述了应该在何时使用设计模式。解决方案描述了设计的组成成分,它们之间的相互关系及各自的职责和协作方式。 设计模式概述 1. 设计模式是什么 我们在平时编写代码的过程中,会遇到各种各样的问题,细想一下很多问题的解决思路大致一样的,这时候你就可以把解决问题的思路整...

    leon 评论0 收藏0

发表评论

0条评论

hlcc

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<