设计模式之行为型模式

模板方法模式(Template)

  • 角色:
    • AbstractClass 抽象类实现了模板方法(template),定义了算法的骨架,具体子类需要去实现 其它的抽象方法ConcreteClass
    • 实现抽象方法 , 以完成算法中特点子类的步骤
    • 使用前

public class CodeTotalTime {

    public static void template(){
        long start = System.currentTimeMillis();
        //        检测Operation_1方法运行的时长======33
        Operation_1();
        //        检测Operation_2方法运行的时长======616
        //        Operation_2();
        long end = System.currentTimeMillis();
        System.out.println(end-start);
    }

    public static void Operation_1(){

        for (int i = 0; i<1000 ;i++){
            System.out.println("模拟耗时操作...");
        }
        System.out.print("检测Operation_1方法运行的时长======");
    }

    public static void Operation_2(){

        for (int i = 0; i<20000 ;i++){
            System.out.println("模拟耗时操作...");
        }

        System.out.print("检测Operation_2方法运行的时长======");
    }

}


public class Client {
    public static void main(String[] args) {
        CodeTotalTime.template();
    }
}

使用后

public abstract class CodeAbstractClass {

    public void template() {
        long start = System.currentTimeMillis();
        method();
        long end = System.currentTimeMillis();
        System.out.println("当前方法执行时长:"+(end - start));
    }

    public abstract void method();

}

class ConcreteClassA extends CodeAbstractClass{

    @Override
    public void method() {
        for (int i = 0; i<1000 ;i++){
            System.out.println("模拟耗时操作...");
        }
        System.out.print("检测ConcreteClassA.method方法运行的时长======");
    }
}

class ConcreteClassB extends CodeAbstractClass{

    @Override
    public void method() {
        for (int i = 0; i<20000 ;i++){
            System.out.println("模拟耗时操作...");
        }
        System.out.print("ConcreteClassB.method方法运行的时长======");
    }
}


public class Client {
    public static void main(String[] args) {
        //检测ConcreteClassA.method方法运行的时长======当前方法执行时长:40
//        new ConcreteClassA().template();
        //ConcreteClassB.method方法运行的时长======当前方法执行时长:272
        new ConcreteClassB().template();
    }
}
  • 钩子函数
    public abstract class CodeAbstractClass {
    
        public void template() {
            long start = System.currentTimeMillis();
            if (callback()) method();
            long end = System.currentTimeMillis();
            System.out.println("当前方法执行时长:" + (end - start));
        }
    
        public abstract void method();
    
        public boolean callback() {
            return true;
        }
    
    }
    

    总结:从上面可以看出:template方法默认是用作统计method方法的执行时长,但是有的时候我们无需统计代码时长,template函数中有一些其它逻辑要执行,在这里我们可以考虑采用钩子函数;钩子函数被子类覆写,覆写成false,那么method方法就不会被调用,不再统计代码时长了;前端框架Vue的生命周期就有多处用到钩子函数;

注意事项和细节:

  • 钩子函数在模板方法模式的父类中,我们可以定义一个方法,它默认不做任何事,子类可以视情况要不要覆盖它,该方法称为“钩子”

  • 算法只存在于一个地方,也就是在父类中,容易修改。需要修改算法时,只要修改父类的模板方法或者已经实现的某些步骤,子类就会继承这些修改

  • 一般模板方法都加上 final 关键字, 防止子类重写模板方法

命令模式(Command)

  • 术语

    • Command:命令

    • ConcreteCommand:具体的命令

    • Invoker:调用者

    • Receiver:接受者

  •  角色
    • Command抽象命令 执行命令 撤销命令

    • ConcreteCommandLightOnCommand 开灯 LightOffCommand 关灯

      ​ NonCommand

      ​ 空命令

    • Invoker调用者 遥控器聚合所有命令 Command[] ons Command[] offs Command undo

    • Receiver接受者 电灯、空调、电视

    •  出现前

      public class Light {
          public void on(){
              System.out.println("电灯打开...");
          }
      
          public void off(){
              System.out.println("电灯关闭...");
          }
      }
      
      class AirConditioner {
          public void on(){
              System.out.println("空调打开...");
          }
      
          public void off(){
              System.out.println("空调关闭...");
          }
      }
      
      class Television {
          public void on(){
              System.out.println("电视打开...");
          }
      
          public void off(){
              System.out.println("电视关闭...");
          }
      }
      
      
      public class Invoker {
          private Light light = new Light();
          private AirConditioner airConditioner = new AirConditioner();
          private Television television = new Television();
      
          public void lightOn(){
              light.on();
          }
      
          public void lightOff(){
              light.off();
          }
      
          public void airOn(){
              airConditioner.on();
          }
      
          public void airOff(){
              airConditioner.off();
          }
      
          public void tvOn(){
              television.on();
          }
      
          public void tvOff(){
              television.off();
          }
      }
      
      public class Client {
          public static void main(String[] args) {
              Invoker invoker = new Invoker();
              invoker.lightOn();
              invoker.lightOff();
              System.out.println("=============");
              invoker.airOn();
              invoker.airOff();
              System.out.println("=============");
              invoker.tvOn();
              invoker.tvOff();
          }
      }

      出现后

      public class Light {
          public void on(){
              System.out.println("电灯打开...");
          }
      
          public void off(){
              System.out.println("电灯关闭...");
          }
      }
      
      class AirConditioner {
          public void on(){
              System.out.println("空调打开...");
          }
      
          public void off(){
              System.out.println("空调关闭...");
          }
      }
      
      class Television {
          public void on(){
              System.out.println("电视打开...");
          }
      
          public void off(){
              System.out.println("电视关闭...");
          }
      }
      
      
      package com.javaxl.design.command.after;
      
      
      interface Command {
          void execute();
      
          void undo();
      }
      
      //空命令
      class NonCommand implements Command {
      
          @Override
          public void execute() {
      
          }
      
          @Override
          public void undo() {
      
          }
      }
      
      class LightOnCommand implements Command {
          private Light light = new Light();
      
          @Override
          public void execute() {
              light.on();
          }
      
          @Override
          public void undo() {
              light.off();
          }
      }
      
      class LightOffCommand implements Command {
          private Light light = new Light();
      
          @Override
          public void execute() {
              light.off();
          }
      
          @Override
          public void undo() {
              light.on();
          }
      }
      
      class TvOnCommand implements Command {
          private Television tv = new Television();
      
          @Override
          public void execute() {
              tv.on();
          }
      
          @Override
          public void undo() {
              tv.off();
          }
      }
      
      class TvOffCommand implements Command {
          private Television tv = new Television();
      
          @Override
          public void execute() {
              tv.off();
          }
      
          @Override
          public void undo() {
              tv.on();
          }
      }
      
      
      public class Invoker {
          Command[] ons;
          Command[] offs;
      //    记录上一个命令
          Command command;
      
          public Invoker(int n) {
              ons = new Command[n];
              offs = new Command[n];
              command = new NonCommand();
              for (int i = 0; i < n; i++) {
                  setCommand(i,new NonCommand(),new NonCommand());
              }
          }
      
          public void setCommand(int no, Command on, Command off){
              ons[no]=on;
              offs[no]=off;
          }
      
          public Command getOnCommand(int no){
              return ons[no];
          }
      
          public Command getOffCommand(int no){
              return offs[no];
          }
      
      //    执行命令
          public void invoke(Command command){
      //        执行当前命令
              command.execute();
      //        保存当前执行命令
              this.command = command;
          }
      
      //    撤销命令(上个操作的反操作)
          public void undo(){
      //        这里就能体现定义一个空命令的好处了,如果第一次按撤销命令,那么应该什么都不做;
      //        如果没有定义空命令的话,此时就需要判断空处理了
              command.undo();
          }
      }
      
      
      public class Client {
          public static void main(String[] args) {
              Invoker invoker = new Invoker(2);
              invoker.setCommand(0, new LightOnCommand(), new LightOffCommand());
              invoker.setCommand(1, new TvOnCommand(), new TvOffCommand());
      
              System.out.println("电灯打开关闭操作===========");
              invoker.invoke(invoker.getOnCommand(0));
              invoker.invoke(invoker.getOffCommand(0));
      //        invoker.undo();
              System.out.println("电视打开关闭操作===========");
              invoker.invoke(invoker.getOnCommand(1));
              invoker.undo();
          }
      }
      

  • 注意事项和细节:

    • 将发起请求的对象与执行请求的对象解耦

      • 容易实现对请求的撤销和重做

      • 空命令也是一种设计模式,它为我们省去了判空的操作

      • 命令模式不足:​ 可能导致某些系统有过多的具体命令类,增加了系统的复杂度

      • 与外观模式相似:都是将多个功能聚合在一起​ 外观模式更多适用于维护;命令模式更多应用于设计;

备忘录模式(Memento)

  • 角色

    • originator :待保存状态的对象 ~ Hero

    • Memento :备忘录对象

    • Caretaker:

      • 存放备忘录对象的容器;可以是List、Map、或者单个Memento对象

      • 可以保存多个 originator 对象的不同时间的状态

情况1:为一个对象保留一个状态  

public class Hero {
  //    需要存档的属性:这里用一个state属性来表示,实际需要存档的属性可能会有很多
      private String state;
  
      public Hero(String state) {
          this.state = state;
      }
  
      public String getState() {
          return state;
      }
  
      public void setState(String state) {
          this.state = state;
      }
  
  //    将当前Hero对象实例进行备份
      public HeroMemento saveHero(){
          return new HeroMemento(this.state);
      }
  
  //    恢复上一个英雄状态
      public void getMemento(HeroMemento heroMemento){
          this.state = heroMemento.getState();
      }
  
  }
  
  
  public class HeroMemento {
      private String state;
  
      public HeroMemento(String state) {
          this.state = state;
      }
  
      public String getState() {
          return state;
      }
  
      public void setState(String state) {
          this.state = state;
      }
  }
  
  
  public class Caretaker {
      private HeroMemento heroMemento;
  
      public HeroMemento getHeroMemento() {
          return heroMemento;
      }
  
      public void setHeroMemento(HeroMemento heroMemento) {
          this.heroMemento = heroMemento;
      }
  }
  
  
  public class Client {
      public static void main(String[] args) {
          Hero hero = new Hero("状态1,满血状态");
          Caretaker caretaker = new Caretaker();
  
          caretaker.setHeroMemento(hero.saveHero());
          hero.setState("状态2:状态下滑");
          System.out.println("当前的状态==============="+hero.getState());
  //        hero.getMemento(caretaker.getHeroMemento());
  //        System.out.println("当前的状态==============="+hero.getState());
  
          caretaker.setHeroMemento(hero.saveHero());
          hero.setState("状态3:残血状态");
          hero.getMemento(caretaker.getHeroMemento());
          System.out.println("当前的状态==============="+hero.getState());
  
          caretaker.setHeroMemento(hero.saveHero());
          hero.setState("状态4:临死状态");
          caretaker.setHeroMemento(hero.saveHero());
  
      }
  }
  • 情况2:为一个对象保留多个状态
 public class Hero {
  //    需要存档的属性:这里用一个state属性来表示,实际需要存档的属性可能会有很多
      private String state;
  
      public Hero(String state) {
          this.state = state;
      }
  
      public String getState() {
          return state;
      }
  
      public void setState(String state) {
          this.state = state;
      }
  
  //    将当前Hero对象实例进行备份
      public HeroMemento saveHero(){
          return new HeroMemento(this.state);
      }
  
  //    恢复某一个英雄状态
      public void getMemento(Caretaker caretaker,int no){
          this.state = caretaker.getMemento(no).getState();
      }
  
  }
  
  
  public class HeroMemento {
      private String state;
  
      public HeroMemento(String state) {
          this.state = state;
      }
  
      public String getState() {
          return state;
      }
  
      public void setState(String state) {
          this.state = state;
      }
  }
  
  
  public class Caretaker {
      private List<HeroMemento> heroMementos = new ArrayList<>();
  
      public void addMemento(HeroMemento memento){
          heroMementos.add(memento);
      }
  
      public HeroMemento getMemento(int no){
          return heroMementos.get(no);
      }
  
  }
  
  
  public class Client {
      public static void main(String[] args) {
          Hero hero = new Hero("状态1,满血状态");
          Caretaker caretaker = new Caretaker();
          caretaker.addMemento(hero.saveHero());
  
          hero.setState("状态2:状态下滑");
  
          hero.setState("状态3:残血状态");
          caretaker.addMemento(hero.saveHero());
  
          hero.setState("状态4:临死状态");
          caretaker.addMemento(hero.saveHero());
  
          hero.setState("状态5:死亡状态");
  
  //        上面备份了1、3、4状态,我来恢复看看
          System.out.println("当前的状态==============="+hero.getState());
          hero.getMemento(caretaker,0);
          System.out.println("回复到状态1==============="+hero.getState());
          hero.getMemento(caretaker,1);
          System.out.println("回复到状态3==============="+hero.getState());
          hero.getMemento(caretaker,2);
          System.out.println("回复到状态4==============="+hero.getState());
  
      }
  }
  • 情况3:为多个对象保留一个状态

    • public class Caretaker {
          private HashMap<Originator ,Memento> mementos = new HashMap();
      }
      

  • 情况4:为多个对象保留多个状态

    • public class Caretaker {
          private HashMap<Originator , List<Memento>> mementos  = new HashMap();
      }
      

  • 注意事项和细节

    • 给用户提供了一种可以恢复状态的机制,可以使用户能够比较方便地回到某个历史的状态

    • 实现了信息的封装,使得用户不需要关心状态的保存细节

    • 注意:如果类的成员变量过多,势必会占用比较大的资源,而且每一次保存都会消耗一定的内存

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值