设计模式行为型模式。

Posted weixin_42412601

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式行为型模式。相关的知识,希望对你有一定的参考价值。

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:这里的EventListener ,直接用的Spring提供的。也可以自己写

以上是关于设计模式行为型模式。的主要内容,如果未能解决你的问题,请参考以下文章

设计模式——行为型模式

设计模式初识行为型模式

设计模式之行为型模式

php设计模式:行为型模式

设计模式——行为型模式

行为型模式:命令模式