Design pattern behavior pattern.

1. Template method pattern

Basic introduction

1) Template Method Pattern, also known as template pattern, defines the template of the method executing it in an abstract class. Its subclasses can override the method implementation as needed, but the call will be made in the way defined in the abstract class.
2) In short, the template method pattern defines the skeleton of an algorithm in operation, and delays some steps to subclasses, so that subclasses can redefine some specific steps of an algorithm without changing the structure of an algorithm
3) This type of design pattern belongs to behavioral pattern.

Main solution: some methods are common, but this method is rewritten in each subclass.
Usage scenario: 1. There are methods shared by multiple subclasses with the same logic. 2. Important and complex methods can be considered as template methods.

For example:

1. Create an abstract class whose template method is set to final.

public abstract class Game {
   abstract void initialize();
   abstract void startPlay();
   abstract void endPlay();
 
   //Template
   public final void play(){
 
      //Initialize game
      initialize();
 
      //Start the game
      startPlay();
 
      //End the game
      endPlay();
   }
}

2. Create an entity class that extends the above class.

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. User

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

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

Hook method of template mode

In the parent class of the template method pattern, we can define a method that does nothing by default, and the subclass can override it according to the situation. This method is called "hook".

For example, we want to make pure soybean milk without adding any ingredients. Please use the hook method to transform the template method

//Abstract class representing soybean milk
public abstract class SoyaMilk {
	//Template methods, make, and template methods can be made final without subclass coverage 
	final void make() {
		select(); 
		if(customerWantCondiments()) {
			addCondiments();
		}
		soak();
		beat();
	}
	//Material selection
	void select() {
		System.out.println("Step 1: choose good fresh soybeans	");
	}
	//Add different ingredients, abstract methods and subclasses
	abstract void addCondiments();
	
	//soak
	void soak() {
		System.out.println("Third, soybeans and ingredients begin to soak, which takes 3 hours ");
	}

	void beat() {
		System.out.println("Step 4: put the soybeans and ingredients into the soybean milk machine to break them	");
	}
	
	//Hook method to determine whether ingredients need to be added 
	boolean customerWantCondiments() {
		return true;
	}
}

Source code analysis of application of template method pattern in Spring framework


Class diagram:

2. Command mode

Command Pattern is a data-driven design pattern, which belongs to behavioral pattern. The request is wrapped in the object in the form of a command and passed to the calling object. Call the object to find the appropriate object that can process the command, pass the command to the corresponding object, and the object executes the command.

Intent: encapsulate a request into an object so that you can parameterize the customer with different requests.

Main solution: in software systems, the behavior requester and behavior implementer are usually closely coupled, but in some cases, such as when it is necessary to record, undo or redo, and deal with transactions, this kind of tightly coupled design that cannot resist changes is not suitable.

Usage scenario: you can use the command mode wherever you think it is a command, for example: 1. Every button in the GUI is a command. 2. Simulate CMD.

Key code: define three roles: 1. received real command execution object 2. Command 3. invoker uses the entry of command object

1. Create command interface:

public interface ICommand {
    void execute();
}

2. Specific command implementation classes

public class CommandA implements ICommand{
    private Receiver receiver;
    public CommandA(Receiver receiver) {
        this.receiver = receiver;
    }
    @Override
    public void execute() {
        System.out.println("CommandA implement .....");
        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: the object that executes the command. How to execute the command

public class Receiver {
    public void execute(){
        System.out.println("Receiver Execute command");
    }
}

4. Invoker: create a command entry and execute the command

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

    public Invoker(ICommand commandA, ICommand commandB) {
        CommandA = commandA;
        CommandB = commandB;
    }
    //Execute command A
    public void orderA(){
        CommandA.execute();
    }
    //Execute command B
    public void orderB(){
        CommandB.execute();
    }
}

5. User

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

The JdbcTemplate of the Spring framework uses the command mode

code analysis

  • StatementCallback interface, similar to command interface
  • class QueryStatementCallback implements StatementCallback,SqlProvider, an anonymous inner class, implements the command interface and also acts as the command receiver
  • The command caller Invoker is JdbcTemplate, in which execute(StatementCallback action) method calls action.. Doinstatement method Different objects implementing statementcallback interface correspond to different doInStatemnt implementation logic
  • In addition, the subclasses that implement the StatementCallback command interface include QueryStatementCallback

3. Visitor mode

1) Visitor Pattern encapsulates some operations that act on the elements of a data structure. It can define new operations that act on these elements without changing the data structure.
2) It mainly separates data structure from data operation to solve the problem of data structure and operation coupling
3) The basic working principle of visitor mode is to add an interface to the visited class to receive visitors
4) The main application scenarios of visitor mode are: you need to perform many different operations on objects in an object structure (these operations are not related to each other). At the same time, you need to avoid these operations "polluting" the classes of these objects. You can choose visitor mode

1. Element defines an accept method to receive a visitor object

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

2. ConcreteElement is a concrete element and implements the accept method

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 is an abstract visitor that declares a visit operation for each class of ConcreteElement in the object structure

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

4. ConcreteVisitor: it is a specific access value to implement each operation declared by Visitor, which is a part of each operation implementation

public class ComputerPartDisplayVisitor implements ComputerPartVisitor{
    @Override
    public void visit(Computer computer) {
        System.out.println("Exhibition computer");
    }
    @Override
    public void visit(Mouse mouse) {
        System.out.println("Display mouse");
    }
    @Override
    public void visit(Keyboard keyboard) {
        System.out.println("Display keyboard");
    }
    @Override
    public void visit(Monitor monitor) {
        System.out.println("Display display");
    }
}

5. User

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

4. Iterator mode

This pattern is used to access the elements of the collection object sequentially without knowing the underlying representation of the collection object.
Main solution: traverse the entire integration object in different ways.
When to use: traverse an aggregate object.
How to solve it: leave the responsibility of swimming between elements to the iterator, not the aggregate object.
Key code: define interface: hasNext, next.
Application example: iterator in JAVA.
Usage scenario: 1. Access the content of an aggregate object without exposing its internal representation. 2. You need to provide multiple traversal methods for aggregate objects. 3. Provide a unified interface for traversing different aggregation structures.

1. Iterator interface

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

2. Returns the Container interface of the iterator

public interface Container {
    Iterator getIterator();
}

3. The entity class that implements the Container interface will be responsible for implementing the Iterator interface.

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. Use

    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. Observer mode

Application scenario: some businesses need to be maintained and modified continuously. If you constantly modify this method, it may cause business logic errors

It breaks the principle of single responsibility and couples a lot of code with attributes.
It breaks the opening and closing principle (extension without modifying the code). For example, when I create an order, I have to send wechat messages. I must modify the code to expand the function, or I have to use this method when I want to modify the logic of sending text messages.

Optimization: disassemble 2, 3 and 4, package them into a class, and then similarly execute them one by one with a for loop. It's observer mode

example:

public class OrderEvent extends ApplicationEvent {
    Long id;
    public OrderEvent(Object source,Long id) {
        super(source);
        this.id = id;
    }
}
// The logic of sending e-mail is put into a class
@Component
public class EmailListener  implements ApplicationListener<OrderEvent> {
    @Override
    public void onApplicationEvent(OrderEvent orderEvent) {
        System.out.println("send emails: " + orderEvent.id);
    }
}
// Put the logic of sending text messages into a class
@Component
public class SmsListener implements ApplicationListener<OrderEvent> {
    @Override
    public void onApplicationEvent(OrderEvent orderEvent) {
        System.out.println("The logic of sending text messages." + orderEvent.id);
    }
}
@Service
public class DeviceBusinessPurposeServiceImpl extends ServiceImpl<DeviceBusinessPurposeMapper, DeviceBusinessPurpose> implements DeviceService {
    @Autowired
    private ApplicationContext applicationContext;
    @Override
    public void createOrder() {
        // Create order
        Long id = 1L;
        System.out.println("Create order");

        // Publish order related events (there are many events in Spring, and the event to be published is the event of OrderEvent)
        // Call the business logic in the class circularly
        applicationContext.publishEvent(new OrderEvent(applicationContext, id));
    }
}
ps: there Event and Listener ,Direct use Spring Provided. You can also write it yourself

Keywords: Java Design Pattern

Added by phaseonemedia on Thu, 06 Jan 2022 17:33:33 +0200