设计模式(四)行为型模式。

目录

1、模板方法模式

基本介绍

1)模板方法模式(Template Method Pattern),又叫模板模式(Template Pattern),在一个抽象类公开定义了执行它的方法的模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。
2)简单说,模板方法模式 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构,就可以重定义该算法的某些特定步骤
3)这种类型的设计模式属于行为型模式。

主要解决:一些方法通用,却在每一个子类都重新写了这一方法。
使用场景: 1、有多个子类共有的方法,且逻辑相同。 2、重要的、复杂的方法,可以考虑作为模板方法。

例如:
设计模式(四)行为型模式。
1、创建一个抽象类,它的模板方法被设置为 final。

public abstract class Game {
   abstract void initialize();
   abstract void startPlay();
   abstract void endPlay();
 
   //模板
   public final void play(){
 
      //初始化游戏
      initialize();
 
      //开始游戏
      startPlay();
 
      //结束游戏
      endPlay();
   }
}

2、创建扩展了上述类的实体类。

public class Cricket extends Game {
   @Override
   void endPlay() {
      System.out.println("Cricket Game Finished!");
   }
   @Override
   void initialize() {
      System.out.println("Cricket Game Initialized! Start playing.");
   }
   @Override
   void startPlay() {
      System.out.println("Cricket Game Started. Enjoy the game!");
   }
}
public class Football extends Game {
   @Override
   void endPlay() {
      System.out.println("Football Game Finished!");
   }
 
   @Override
   void initialize() {
      System.out.println("Football Game Initialized! Start playing.");
   }
 
   @Override
   void startPlay() {
      System.out.println("Football Game Started. Enjoy the game!");
   }
}

3、使用者

public class TemplatePatternDemo {
   public static void main(String[] args) {

      Game game = new Cricket();
      game.play();
      game = new Football();
      game.play();      
   }
}

模板方法模式的钩子方法

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

比如,我们希望制作纯豆浆,不添加任何的配料,请使用钩子方法对模板方法进行改造

//抽象类,表示豆浆
public abstract class SoyaMilk {
	//模板方法, make , 模板方法可以做成 final , 不让子类去覆盖. 
	final void make() {
		select(); 
		if(customerWantCondiments()) {
			addCondiments();
		}
		soak();
		beat();
	}
	//选材料
	void select() {
		System.out.println("第一步:选择好的新鲜黄豆	");
	}
	//添加不同的配料, 抽象方法,  子类具体实现
	abstract void addCondiments();
	
	//浸泡
	void soak() {
		System.out.println("第三步, 黄豆和配料开始浸泡, 需要 3 小时 ");
	}

	void beat() {
		System.out.println("第四步:黄豆和配料放到豆浆机去打碎	");
	}
	
	//钩子方法,决定是否需要添加配料 
	boolean customerWantCondiments() {
		return true;
	}
}

模板方法模式在 Spring 框架应用的源码分析

设计模式(四)行为型模式。
设计模式(四)行为型模式。

类图:
设计模式(四)行为型模式。

2、命令模式

命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。

意图:将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化。

主要解决:在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时,这种无法抵御变化的紧耦合的设计就不太合适。

使用场景:认为是命令的地方都可以使用命令模式,比如: 1、GUI 中每一个按钮都是一条命令。 2、模拟 CMD。

关键代码:定义三个角色:1、received 真正的命令执行对象 2、Command 3、invoker 使用命令对象的入口

1、创建command接口:

public interface ICommand {
    void execute();
}

2、具体的命令实现类

public class CommandA implements ICommand{
    private Receiver receiver;
    public CommandA(Receiver receiver) {
        this.receiver = receiver;
    }
    @Override
    public void execute() {
        System.out.println("CommandA 执行 .....");
        receiver.execute();
    }
}

public class CommandB implements ICommand{
    private Receiver receiver;

    public CommandB(Receiver receiver) {
        this.receiver = receiver;
    }
    @Override
    public void execute() {
        System.out.println("CommandB execute ...");
        receiver.execute();
    }
}

3、Receiver:执行命令的对象,具体怎么执行命令

public class Receiver {
    public void execute(){
        System.out.println("Receiver 执行命令");
    }
}

4、Invoker:创建命令入口,执行命令

public class Invoker {
    private ICommand CommandA;
    private ICommand CommandB;

    public Invoker(ICommand commandA, ICommand commandB) {
        CommandA = commandA;
        CommandB = commandB;
    }
    //执行命令A
    public void orderA(){
        CommandA.execute();
    }
    //执行命令B
    public void orderB(){
        CommandB.execute();
    }
}

5、使用者

    public static void main(String[] args) {
        Receiver receiver = new Receiver();
        Invoker invoker = new Invoker(new CommandA(receiver), new CommandB(receiver));
        invoker.orderA();
        invoker.orderB();
    }

Spring 框架的 JdbcTemplate 就使用到了命令模式

代码分析
设计模式(四)行为型模式。

  • StatementCallback 接口 ,类似命令接口(Command)
  • class QueryStatementCallback implements StatementCallback,SqlProvider , 匿名内部类, 实现了命令接口, 同时也充当命令接收者
  • 命令调用者Invoker是 JdbcTemplate , 其中 execute(StatementCallback action)方法中,调用 action.doInStatement 方法. 不同的实现 StatementCallback接口的对象,对应不同的doInStatemnt 实现逻辑
  • 另外实现 StatementCallback 命令接口的子类还有 QueryStatementCallback、

3、访问者模式

1)访问者模式(Visitor Pattern),封装一些作用于某种数据结构的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。
2)主要将数据结构与数据操作分离,解决 数据结构和操作耦合性问题
3)访问者模式的基本工作原理是:在被访问的类里面加一个对外提供接待访问者的接口
4)访问者模式主要应用场景是:需要对一个对象结构中的对象进行很多不同操作(这些操作彼此没有关联),同时需要避免让这些操作"污染"这些对象的类,可以选用访问者模式解决

1、Element 定义一个 accept 方法,接收一个访问者对象

public interface ComputerPart {
    void accept(ComputerPartVisitor  computerPartVisitor);
}

2、ConcreteElement 为具体元素,实现了 accept 方法

public class Computer implements ComputerPart{
    ComputerPart[] parts;
    public Computer() {
        this.parts = new ComputerPart[]{new Mouse(),new Keyboard(),new Monitor()};
    }
    @Override
    public void accept(ComputerPartVisitor computerPartVisitor) {
        for (int i = 0; i < parts.length; i++) {
            parts[i].accept(computerPartVisitor);
        }
        computerPartVisitor.visit(this);
    }
}
public class Keyboard implements ComputerPart{
    @Override
    public void accept(ComputerPartVisitor computerPartVisitor) {
        computerPartVisitor.visit(this);
    }
}
public class Monitor  implements ComputerPart {
   @Override
   public void accept(ComputerPartVisitor computerPartVisitor) {
      computerPartVisitor.visit(this);
   }
}
public class Mouse  implements ComputerPart {
   @Override
   public void accept(ComputerPartVisitor computerPartVisitor) {
      computerPartVisitor.visit(this);
   }
}

3、Visitor 是抽象访问者,为该对象结构中的 ConcreteElement 的每一个类声明一个 visit 操作

public interface ComputerPartVisitor {
    void visit(Computer computer);
    void visit(Mouse mouse);
    void visit(Keyboard keyboard);
    void visit(Monitor monitor);
}

4、ConcreteVisitor :是一个具体的访问值 实现每个有 Visitor 声明的操作,是每个操作实现的部分.

public class ComputerPartDisplayVisitor implements ComputerPartVisitor{
    @Override
    public void visit(Computer computer) {
        System.out.println("展示 computer");
    }
    @Override
    public void visit(Mouse mouse) {
        System.out.println("展示鼠标");
    }
    @Override
    public void visit(Keyboard keyboard) {
        System.out.println("展示键盘");
    }
    @Override
    public void visit(Monitor monitor) {
        System.out.println("展示显示器");
    }
}

5、使用者

   public static void main(String[] args) {
      ComputerPart computer = new Computer();
      computer.accept(new ComputerPartDisplayVisitor());
   }

4、迭代器模式

这种模式用于顺序访问集合对象的元素,不需要知道集合对象的底层表示。
主要解决:不同的方式来遍历整个整合对象。
何时使用:遍历一个聚合对象。
如何解决:把在元素之间游走的责任交给迭代器,而不是聚合对象。
关键代码:定义接口:hasNext, next。
应用实例:JAVA 中的 iterator。
使用场景: 1、访问一个聚合对象的内容而无须暴露它的内部表示。 2、需要为聚合对象提供多种遍历方式。 3、为遍历不同的聚合结构提供一个统一的接口。

1、Iterator 接口

public interface Iterator {
    boolean hasNext();
    Object  next();
}

2、返回迭代器的 Container 接口

public interface Container {
    Iterator getIterator();
}

3、实现了 Container 接口的实体类将负责实现 Iterator 接口。

public class NameRepository implements Container{
    public String[] names={"robert","john","julie","lora"};
    @Override
    public Iterator getIterator() {
        return new NameIterator();
    }
    private class NameIterator implements Iterator{
        int index;
        @Override
        public boolean hasNext() {
            if (index<names.length){
                return true;
            }
            return false;
        }
        @Override
        public Object next() {
            if (this.hasNext()){
                return names[index++];
            }
            return null;
        }
    }
}

4、使用

    public static void main(String[] args) {
        NameRepository nameRepository=new NameRepository();
        Iterator iterator = nameRepository.getIterator();
        while(iterator.hasNext()){
            String name = (String)iterator.next();
            System.out.println("Name : " + name);
        }
    }

5、观察者模式

应用场景:有些业务需要不断的被维护,修改。如果不断的去修改这个方法,可能会造成业务逻辑出错
设计模式(四)行为型模式。
破坏了单一职责原则,耦合了很多附属性的代码。
破坏了开闭原则(不修改代码的情况下进行扩展),比如:我创建订单的时候,还要发微信消息,肯定要修改代码来扩展功能,又或者我要修改发短信的逻辑的时候,又要动这个方法。

优化:把2,3,4拆出来,分别包到一个类里,然后类似的用一个for循环一个一个的去执行。就是观察者模式

例子:

public class OrderEvent extends ApplicationEvent {
    Long id;
    public OrderEvent(Object source,Long id) {
        super(source);
        this.id = id;
    }
}
// 发邮件的逻辑放到一个类里
@Component
public class EmailListener  implements ApplicationListener<OrderEvent> {
    @Override
    public void onApplicationEvent(OrderEvent orderEvent) {
        System.out.println("发邮件: " + orderEvent.id);
    }
}
// 发短信的逻辑放到一个类里
@Component
public class SmsListener implements ApplicationListener<OrderEvent> {
    @Override
    public void onApplicationEvent(OrderEvent orderEvent) {
        System.out.println("发送短信的逻辑。" + orderEvent.id);
    }
}
@Service
public class DeviceBusinessPurposeServiceImpl extends ServiceImpl<DeviceBusinessPurposeMapper, DeviceBusinessPurpose> implements DeviceService {
    @Autowired
    private ApplicationContext applicationContext;
    @Override
    public void createOrder() {
        // 创建订单
        Long id = 1L;
        System.out.println("创建订单");

        // 发布订单相关事件(Spring里有很多事件,指定要发布的事件是OrderEvent的事件)
        // 循环调用类里的业务逻辑
        applicationContext.publishEvent(new OrderEvent(applicationContext, id));
    }
}
ps:这里的Event和Listener ,直接用的Spring提供的。也可以自己写
上一篇:Springboot使用Mybatis实现完整的 增删改查 CRUD和分页


下一篇:java的重写(override)与重载(overload)