It seems that one mode per day is too slow and lacks content, so try 3-4 modes per article and make it better in 2 days.
First of all, commonly used design patterns are divided into three categories: creation patterns, behavior patterns and structural patterns. The factory and Builder patterns written in the previous two articles are part of the creation pattern.
Chain of Responsibility model
The chain of responsibility model can be split into responsibility and chain, responsibility is the responsibility to do something, chain can refer to the linked list, there is a next level.
Scenario: Now you are an employee of a company, and you have received an urgent document (the urgency of documents must be different), and you need a higher level of management to process the document.
Normal mode
File types:
public class File {
private FileClass fileClass; // The importance level of the file
private String content; // The contents of the file
/ / to omit
}
// Enumeration classes represent the importance level of a file
enum FileClass {
NORMAL,
IMPORTANT,
EMERGENCY
}
Copy the code
Employee interface:
public interface IStaff {
// Get the employee's name
public String getName(a);
// Get the level of the file to process
public FileClass getFileClass(a);
// Capture employee needs
public String getRequest(a);
}
Copy the code
Staff:
public class Staff implements IStaff {
private File file;
private String name;
// omit the constructor
@Override
public String getName(a) {
return name;
}
@Override
public FileClass getFileClass(a) {
return file.getFileClass();
}
@Override
public String getRequest(a) {
return "This document [" + file.getContent() +"】 Needs to be dealt with."; }}Copy the code
Leadership interface:
public interface IHandler {
// Process files
public void handle(IStaff staff);
}
Copy the code
The group leader:
public class Leader implements IHandler {
@Override
public void handle(IStaff staff) {
System.out.println(staff.getName() + ":" + staff.getRequest());
System.out.println("Leader: Deal with it now"); }}Copy the code
Director:
public class Director implements IHandler{
@Override
public void handle(IStaff staff) {
System.out.println(staff.getName() + ":" + staff.getRequest());
System.out.println("Director: Deal with it now"); }}Copy the code
Director:
public class Supervisor implements IHandler {
@Override
public void handle(IStaff staff) {
System.out.println(staff.getName() + ":" + staff.getRequest());
System.out.println("Supervisor: Deal with it now"); }}Copy the code
Client:
public class Client {
public static void main(String[] args) {
File file = new File(FileClass.IMPORTANT, "Planning scheme");
IStaff staff = new Staff(file, "imperfect");
if(file.getFileClass().equals(FileClass.NORMAL)) {
new Leader().handle(staff);
} else if(file.getFileClass().equals(FileClass.IMPORTANT)) {
new Director().handle(staff);
} else if(file.getFileClass().equals(FileClass.EMERGENCY)) {
new Supervisor().handle(staff);
} else {
System.out.println("Insufficient authority"); }}}Copy the code
Take a look, and look carefully, this bunch of if else’s are exposed directly in the Client class, and it’s in the Client class that the judgment is made that different levels are handled by different leaders.
The common metaphor is that after the employee gets the document, he calls his team leader, director and supervisor to him and says, “This document is very important. Who can handle it for you?” It is possible to complete characters, but is it realistic?
One way to approach reality is for employees to get the file and first give it to their immediate leader, the lowest level in the hierarchy (handler). Then the group leader will see if he is responsible to deal with the documents, if not, then to the next layer to deal with, this is the responsibility chain mode.
Chain of Responsibility model
The file and employee classes remain the same, with handler being the main change.
Abstract Leadership class:
public abstract class AbstractHandler {
private FileClass fileClass;
private AbstractHandler nextHandler;
private String name;
// The responsibilities are specified when the class is constructed
// Just like you know what your responsibilities are when you enter the company
public AbstractHandler(FileClass fileClass, String name) {
this.fileClass = fileClass;
this.name = name;
}
// Get the name of the leader
public String getName(a) {
return name;
}
// No responsibility, pass to the next level
public void setNextHandler(AbstractHandler nextHandler) {
this.nextHandler = nextHandler;
}
// Everyone responds differently, so abstract it out
public abstract void respond(IStaff staff);
// Process information
public void handle(IStaff staff) {
if(fileClass.equals(staff.getFileClass())) {
respond(staff);
} else {
if(nextHandler ! =null) {
nextHandler.respond(staff);
} else {
System.out.println("Maximum clearance!!"); }}}}Copy the code
The group leader:
public class Leader extends AbstractHandler {
public Leader(String name) {
super(FileClass.NORMAL, name);
}
@Override
public void respond(IStaff staff) {
System.out.println(staff.getName() + ":" + staff.getRequest());
System.out.println(getName() + "Leader: Responded."); }}Copy the code
Director:
public class Director extends AbstractHandler{
public Director(String name) {
super(FileClass.IMPORTANT, name);
}
@Override
public void respond(IStaff staff) {
System.out.println(staff.getName() + ":" + staff.getRequest());
System.out.println(getName() + "Director: Responded."); }}Copy the code
Director:
public class Supervisor extends AbstractHandler {
public Supervisor(String name) {
super(FileClass.EMERGENCY, name);
}
@Override
public void respond(IStaff staff) {
System.out.println(staff.getName() + ":" + staff.getRequest());
System.out.println(getName() + "Supervisor: Responded."); }}Copy the code
Client:
public class Client {
public static void main(String[] args) {
File file = new File(FileClass.IMPORTANT, "Marketing plan");
IStaff staff = new Staff(file, "imperfect");
// Create leadership
AbstractHandler leader = new Leader("leaderWu");
AbstractHandler director = new Director("directorWu");
AbstractHandler supervisor = new Supervisor("supervisorWu");
// Set the hierarchy, similar to a linked list
leader.setNextHandler(director);
director.setNextHandler(supervisor);
// Let's give it to our direct managerleader.handle(staff); }}Copy the code
The advantages and disadvantages
- ** Advantages: ** Processing and requests are separated, and employees do not know who is handling the final document
- ** Disadvantages: ** disadvantages are also obvious, if the chain of responsibilities is long, and the processor happens to be at the end, do not need to go through the chain of responsibilities. This performance is relatively low, in actual use, generally fold this maximum chain length to ensure performance.
UML class diagrams
Command mode
Command mode, in a word, is to give you an order, you must obey and execute, a bit like the army “obey orders is the bountiful duty of soldiers”.
I don’t know if I have ever participated in mathematical modeling in university. Anyway, I have never participated in mathematical modeling, but I have learned about the general composition. There are generally students who are mainly responsible for searching, students who write codes, students who write papers and teachers in a team
Normal mode
Abstract Member class (Receiver) :
public abstract class NTeammate {
public abstract void changeRequire(a);
public abstract void modify(a);
public abstract void work(a);
}
Copy the code
Searcher:
public class NSearcher extends NTeammate {
@Override
public void changeRequire(a) {
System.out.println("Searcher learns that demand has changed.");
}
@Override
public void modify(a) {}@Override
public void work(a) {
System.out.println("Searcher starts searching for relevant information."); }}Copy the code
Writer:
public class NWriter extends NTeammate {
@Override
public void changeRequire(a) {
System.out.println("Writer understands the need to change");
}
@Override
public void modify(a) {
System.out.println("Writer revises the paper");
}
@Override
public void work(a) {
System.out.println("Writer begins to write a paper"); }}Copy the code
Coder:
public class NCoder extends NTeammate {
@Override
public void changeRequire(a) {
System.out.println("Coder understands the requirements are changing.");
}
@Override
public void modify(a) {
System.out.println("Coder modify code");
}
@Override
public void work(a) {
System.out.println("Coder start code"); }}Copy the code
Teacher:
public class NTeacher {
public static void main(String[] args) {
NTeammate writer = new NWriter();
// I need to change my articlewriter.modify(); writer.work(); }}Copy the code
At the beginning, the Teacher saw that the text was not concise enough, so he called writer and asked him to modify it, so the Teacher class above was created. This is actually good, because the article, revise and polish.
One day later, the teacher took a closer look and found a bug in the algorithm of the code. This bug caused not only the coder to modify the code, but also the writer to modify the corresponding article.
The Teacher should contact not only writer, but also coder. Then how should the Teacher class be modified?
public class NTeacher {
public static void main(String[] args) {
NTeammate writer = new NWriter();
NTeammate coder = new NCoder();
// Need to fix bugs and articleswriter.modify(); writer.work(); coder.modify(); coder.work(); }}Copy the code
As you can see, there is just one more requirement, and the code has changed a lot from before, which we don’t want to see. Some of you might think of using the mediator pattern, but the mediator pattern is to reduce the coupling between classes, and in this case the searcher, writer, and coder are not coupled, they are all doing their job.
Command mode
It would be nice if there were an Invoker in the squad, which can communicate with the teacher (client). Not only that, but the teacher’s instructions must be of String type when implemented. We can encapsulate the instructions as a class (command), and the captain only needs to issue commands, which instruct the players (receiver) what to do. This is the command mode, the team members must do what they are told to do.
Abstract players and concrete players are the same as above, so I won’t repeat them here.
Abstract command class:
public abstract class AbstractCommand {
protected Coder coder = new Coder();
protected Searcher searcher = new Searcher();
protected Writer writer = new Writer();
// There must be a way to execute, a command
public abstract void execute(a);
}
Copy the code
Specific Command classes:
All commands can be encapsulated
Changing requirements:
public class ChangeInfoCommand extends AbstractCommand {
@Override
public void execute(a) { searcher.changeRequire(); writer.changeRequire(); coder.changeRequire(); }}Copy the code
Modify the article:
public class ModifyArticleCommand extends AbstractCommand {
@Override
public void execute(a) { writer.modify(); writer.work(); }}Copy the code
Modify code:
public class ModifyCodeCommand extends AbstractCommand {
@Override
public void execute(a) { coder.modify(); coder.work(); writer.modify(); writer.work(); }}Copy the code
Captain class (Invoke) :
public class Captain {
// Create a connection with the command
AbstractCommand abstractCommand;
public Captain(AbstractCommand abstractCommand) {
this.abstractCommand = abstractCommand;
}
public void invoke(a) {
// Issue an order for the team member to do the corresponding actionabstractCommand.execute(); }}Copy the code
Teacher (Client) :
public class Teacher {
public static void main(String[] args) {
AbstractCommand command = new ModifyCodeCommand();
Captain captain = newCaptain(command); captain.invoke(); }}Copy the code
If the teacher feels bad again, how to do this? There is no need to practice with the members, just put forward another suggestion. The captain does not practice with the members, just issue orders, and the orders instruct the members to do it. Modification is as simple as that, a line of code.
public class Teacher {
public static void main(String[] args) {
//AbstractCommand command = new ModifyCodeCommand();
AbstractCommand command = new ModifyArticleCommand();
Captain captain = newCaptain(command); captain.invoke(); }}Copy the code
extension
What if, alas, code changes not only require bug fixes and article fixes, but also require searchers to gather information?
public class ModifyCodeCommand extends AbstractCommand {
@Override
public void execute(a) {
searcher.work(); // Just add it in the specific command, the client is completely unaware of itcoder.modify(); coder.work(); writer.modify(); writer.work(); }}Copy the code
Another case is that after some modifications, the teacher finds that the previous version is better, which requires each member to have a callback function to undo the action and return to the previous state, that is, to find the saved file of the previous version. Just add a callback function to the abstract Receiver class:
public abstract class NTeammate {
public abstract void changeRequire(a);
public abstract void modify(a);
public abstract void work(a);
// Specific teammates are implementing callback methods in their own way
public abstract void rollback(a);
}
Copy the code
Then you add a recall command
public class callBackCommand extends AbstractCommand {
@Override
public void execute(a) {
// Of course, who needs to withdraw can be changedsearcher.rollback(); writer.rollback(); coder.rollback(); }}Copy the code
UML class diagrams
Interpreter mode
This design pattern is quite unpopular in both work and study. The interpreter pattern consists of the following classes
- Context: The Context encapsulates global information about the interpreter. All specific interpreters need to access the Context.
- AbstractExpression: An abstract class or interface that declares interpretive methods to perform, implemented by all concrete interpreters
- TerminalExpression: An interpreter class that implements operations related to the terminator of a grammar. A terminator expression must be implemented and instantiated because it represents the end of the expression.
- NonTerminalExpreesion: This is a class that implements the different rules or symbols of the syntax. You should create a class for each syntax.
This thing is difficult to explain, there is no good popular explanation, so just look at the example.
AbstractExpression
public interface Expression {
public float interpret(a);
}
Copy the code
TerminalExpression
public class Number implements Expression{
private final float number;
public Number(float number) {
this.number = number;
}
@Override
public float interpret(a) {
returnnumber; }}Copy the code
Remember when we talked about streams, TerminalExpression is like a terminaloperation, and NonTerminalExpression is like an intermediate operation
NonTerminalExpression
public class Plus implements Expression{
Expression left;
Expression right;
public Plus(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public float interpret(a) {
returnleft.interpret() + right.interpret(); }}Copy the code
Note that there is a separate class for each syntax
public class Minus implements Expression {
Expression left;
Expression right;
public Minus(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public float interpret(a) {
returnleft.interpret() - right.interpret(); }}Copy the code
Context
public class Evaluator {
public static void main(String[] args) {
Evaluator evaluator = new Evaluator();
System.out.println(evaluator.evaluate("3 4 +"));
System.out.println(evaluator.evaluate("3-4"));
System.out.println(evaluator.evaluate("4, 3-2 +"));
}
public float evaluate(String expression) {
Stack<Expression> stack = new Stack<>();
float result = 0;
for (String token : expression.split("")) {
Expression exp = null;
if (isOperator(token)) {
if (token.equals("+")) {
exp = stack.push(new Plus(stack.pop(), stack.pop()));
} else if (token.equals("-")) {
exp = stack.push(new Minus(stack.pop(), stack.pop()));
}
if (null! = exp) { result = exp.interpret(); stack.push(newNumber(result)); }}if (isNumber(token)) {
stack.push(newNumber(Float.parseFloat(token))); }}return result;
}
private boolean isNumber(String token) {
try {
Float.parseFloat(token);
return true;
} catch (NumberFormatException e) {
return false; }}private boolean isOperator(String token) {
return token.equals("+") || token.equals("-"); }}Copy the code