5 minutes per day – behavioral mode (1)

Time:2021-10-24

It seems that the rhythm of one mode every day is a little too slow and the content is a little less, so I’d better try 3 – 4 modes per article, and then make it better every two days.

Firstly, the commonly used design patterns are divided into three categories: creation pattern, behavior pattern and structure pattern. The factory mode and builder mode written in the first two articles belong to the content of creation mode.

Responsibility chain model

The responsibility chain model can be divided into responsibility and chain. Responsibility refers to what you have responsibility to do. The chain can refer to the chain list, and there is a next level.

scene: now that you are an employee of a company and have got a relatively urgent document (the urgency of the document must be different), you need a higher level of leadership to deal with the document.

Normal mode

File class:

public class File {

    private FileClass fileClass;    // Importance level of documents
    private String content;            // Contents of the document

    //Omit

}

//The enumeration class represents the importance level of the file
enum FileClass {
    NORMAL,
    IMPORTANT,
    EMERGENCY
}

Employee interface:

public interface IStaff {
    //Get employee's name
    public String getName();
    
    //Gets the level of the file to process
    public FileClass getFileClass();
    
    //Get the needs of employees
    public String getRequest();    
}

Employees:

public class Staff implements IStaff {
    private File file;
    private String name;

    //Omit constructor

    @Override
    public String getName() {
        return name;
    }

    @Override
    public FileClass getFileClass() {
        return file.getFileClass();
    }

    @Override
    public String getRequest() {
        Return "this file [" + file. Getcontent() + "] needs to be processed";
    }
}

Leadership interface:

public interface IHandler {
    //Processing files
    public void handle(IStaff staff);
}

group leader:

public class Leader implements IHandler {
    @Override
    public void handle(IStaff staff) {
        System.out.println(staff.getName() + ": " + staff.getRequest());
        System.out.println ("team leader: handle now");
    }
}

chief inspector:

public class Director implements IHandler{
    @Override
    public void handle(IStaff staff) {
        System.out.println(staff.getName() + ": " + staff.getRequest());
        System.out.println ("director: handle now");
    }
}

executive director:

public class Supervisor implements IHandler {
    @Override
    public void handle(IStaff staff) {
        System.out.println(staff.getName() + ": " + staff.getRequest());
        System.out.println ("supervisor: handle now");
    }
}

Client:

public class Client {
    public static void main(String[] args) {
        File = new file (fileclass. Import, "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 permission");
        }
        
    }
}

You see, carefully, this pile of if else is directly exposed in the client class, and it is only in the client that judgment is made, and different levels are handled by different leaders.

In a popular analogy, employees call their team leader, director and supervisor to themselves after they get the document, and then say that this document is more important. Who will have the authority to deal with it. It is true that characters can be completed, but is this way realistic?

5 minutes per day - behavioral mode (1)

What is the way to approach the reality? After employees get the documents, they first give them to their direct leader, the team leader, and the leadership(handler)The lowest layer in the(Chain head)。 Then the team leader will see if he hasresponsibilityTo process files, if not, to the next level to process, this isResponsibility chain model

Responsibility chain model

The file class and Employee class remain unchanged, mainly due to the change of the handler.

Abstract leadership class:

public abstract class AbstractHandler {
    private FileClass fileClass;
    private AbstractHandler nextHandler;
    private String name;

    //The responsibilities are defined when the class is constructed
    //It's like you know what documents you're responsible for when you start
    public AbstractHandler(FileClass fileClass, String name) {
        this.fileClass = fileClass;
        this.name = name;
    }

    //Get the leader's name
    public String getName() {
        return name;
    }

    //No responsibility, leave it to the next level
    public void setNextHandler(AbstractHandler nextHandler) {
        this.nextHandler = nextHandler;
    }

    //When dealing with responses, everyone responds in different ways, so it is abstracted
    public abstract void respond(IStaff staff);

    //Processing information
    public void handle(IStaff staff) {
        if(fileClass.equals(staff.getFileClass())) {
            respond(staff);
        } else {
            if(nextHandler != null) {
                nextHandler.respond(staff);
            } else {
                System. Out. Println ("the highest permission has been reached!!!");
            }
        }
    }

}

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() + "team leader: responded");
    }
}

chief inspector:

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");
    }
}

executive 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");
    }
}

Client:

public class Client {
    public static void main(String[] args) {
        File file = new file (fileclass. Import, "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 hierarchical relationship, similar to the linked list
        leader.setNextHandler(director);
        director.setNextHandler(supervisor);

        //First, hand it over to the direct leader
        leader.handle(staff);
        
    }
}

Advantages and disadvantages

  • advantage:Processing and request are separated, and employees do not know who handled the final documents
  • Disadvantages:The disadvantages are also very obvious. If the responsibility chain is very long and the handler is just at the end, do you want to traverse the responsibility chain. In this way, the performance is relatively low. In actual use, the maximum chain length is generally folded to ensure the performance.

UML class diagram

5 minutes per day - behavioral mode (1)

Command mode

Command mode, in a word, is to give you an order, which must be observed and implemented. It is a bit like “obeying orders is the bounden duty of soldiers” in the army.

I don’t know whether the university has participated in mathematical modeling. Anyway, I haven’t participated in it, but I have learned about the general composition. Generally, there are main responsibilities in a teamStudents who search, students who write code, students who write papers and instructors

Normal mode

Abstract member class (receiver):

public abstract class NTeammate {

    public abstract void changeRequire();

    public abstract void modify();

    public abstract void work();

}

Searcher:

public class NSearcher extends NTeammate {
    @Override
    public void changeRequire() {
        System.out.println ("searcher understands the change of requirements");
    }

    @Override
    public void modify() {

    }

    @Override
    public void work() {
        System.out.println ("searcher starts searching for relevant information");
    }
}

Writer:

public class NWriter extends NTeammate {
    @Override
    public void changeRequire() {
        System. Out. Println ("the writer understands the requirements change");
    }

    @Override
    public void modify() {
        System.out.println ("writer modifies the paper");
    }

    @Override
    public void work() {
        System. Out. Println ("writer starts writing papers");
    }
}

Coder:

public class NCoder extends NTeammate {
    @Override
    public void changeRequire() {
        System. Out. Println ("coder understands the change of requirements");
    }

    @Override
    public void modify() {
        System.out.println ("coder modification code");
    }

    @Override
    public void work() {
        System.out.println ("coder start code");
    }
}

Teacher:

public class NTeacher {
    public static void main(String[] args) {
        NTeammate writer = new NWriter();
        //The article needs to be changed
        writer.modify();
        writer.work();
    }
}

At the beginning, the teacher saw that the written exhibition was not concise enough, so he called the writer and asked him to modify it, so there was the teacher class above. In fact, it’s OK, because the article should be modified and polished.

After a day, the teacher looked carefully and found that there was a bug in the algorithm of the code. This vulnerability led not only to the coder to modify the code, but also to the writer to modify the articles in the corresponding places.

5 minutes per day - behavioral mode (1)

The teacher has to contact not only the writer but also the coder. 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 articles
        writer.modify();
        writer.work();
        
        coder.modify();
        coder.work();
        
    }
}

It can be found that there is one more requirement, and the code has been greatly changed than before, which we don’t want to see. Some small partners may think of using the mediator mode, but the mediator mode is to reduce the coupling between classes. In this example, the searcher, writer and coder are not coupled and are performing their respective duties.

Command mode

If there’s a captain in the team(Invoker)That’s good. You can talk to the teacher(client)More than that, the teacher’s instructions must be of string type. We can encapsulate the instructions as a class(command), the captain only needs to issue orders to instruct the team members(receiver)To do something. This is the command mode. The team members must perform what the command requires.

Abstract team members and specific team members are still the same as above, which will not be repeated 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 and issue an order
    public abstract void execute();
}

Specific command class:

What commands can be encapsulated

Change needs:

public class ChangeInfoCommand extends AbstractCommand {
    @Override
    public void execute() {
        searcher.changeRequire();
        writer.changeRequire();
        coder.changeRequire();
    }
}

Modify article:

public class ModifyArticleCommand extends AbstractCommand {
    @Override
    public void execute() {
        writer.modify();
        writer.work();
    }
}

Modification code:

public class ModifyCodeCommand extends AbstractCommand {
    @Override
    public void execute() {
        coder.modify();
        coder.work();
        writer.modify();
        writer.work();
    }
}

Captain class (invoke):

public class Captain {
    //Contact with the command
    AbstractCommand abstractCommand;

    public Captain(AbstractCommand abstractCommand) {
        this.abstractCommand = abstractCommand;
    }

    public void invoke() {
        //Issue orders to ask the team members to take corresponding actions
        abstractCommand.execute();
    }

}

Teacher class (client):

public class Teacher {
    public static void main(String[] args) {
        AbstractCommand command = new ModifyCodeCommand();
        Captain captain = new Captain(command);
        captain.invoke();
    }
}

If the teacher thinks it’s bad again, what should we do? There’s no need to practice with the members. Just put forward another suggestion. The captain doesn’t practice with the team members, just issue an order and instruct the team members to do it. Modification is so simple, a line of code.

public class Teacher {
    public static void main(String[] args) {
        //AbstractCommand command = new ModifyCodeCommand();
        AbstractCommand command = new ModifyArticleCommand();
        Captain captain = new Captain(command);
        captain.invoke();
    }
}

extend

What if, eh, when changing code, you not only need to modify bugs and articles, but also need searcher to collect information?

public class ModifyCodeCommand extends AbstractCommand {
    @Override
    public void execute() {
        searcher.work();    // Just add it in the specific command, and the client doesn't know it at all
        coder.modify();
        coder.work();
        writer.modify();
        writer.work();
    }
}

In another case, after some modifications, the teacher finds that the previous version is better, which requires each team 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();

    public abstract void modify();

    public abstract void work();
    
    //Specific teammates are implementing callback methods in their own way
    public abstract void rollback();

}

Then add oneWithdraw order

public class callBackCommand extends AbstractCommand {
    @Override
    public void execute() {
        //Of course, who needs to withdraw can be changed
        searcher.rollback();
        writer.rollback();
        coder.rollback();
    }
}

UML class diagram

5 minutes per day - behavioral mode (1)

Interpreter mode

This is a popular design mode both in work and study. The Interpreter pattern consists of the following classes

  • Context:Context is used to encapsulate the global information of the interpreter. All specific interpreters need to access context.
  • AbstractExpression:An abstract class or interface, which declares the interpretation method to be executed, and is implemented by all concrete interpreters
  • TerminalExpression:An interpreter class that implements operations related to syntax terminators. The terminator expression must be implemented and instantiated because it represents the end of the expression.
  • NonTerminalExpreesion:This is a class that implements different rules or symbols of syntax. A class should be created for each syntax.

This thing is difficult to explain, and there is no good popular explanation for the moment. Let’s look at the example directly.

AbstractExpression

public interface Expression {
    public float interpret();
}

TerminalExpression

public class Number implements Expression{
    private final float number;

    public Number(float number) {
        this.number = number;
    }

    @Override
    public float interpret() {
        return number;
    }
}

Remember the flow mentioned before,TerminalExpressionIt’s like terminating an operation, andNonTerminalExpressionIt is similar to 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() {
        return left.interpret() + right.interpret();
    }
}

Note that there should be 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() {
        return left.interpret() - right.interpret();
    }
}

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("4 3 -"));
        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(new Number(result));
                }
            }

            if (isNumber(token)) {
                stack.push(new Number(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("-");
    }
    
}

UML class diagram

5 minutes per day - behavioral mode (1)

5 minutes per day - behavioral mode (1)