23 Design Patterns Study Notes (7)

Hits: 0

23 Design Pattern Study Notes (1)
/qq_51495235/article/details/115358623

23 Design Pattern Study Notes (2)
/qq_51495235/article/details /115358846

23 Design Pattern Study Notes (3)
/qq_51495235/article/details/115359128

23 Design Pattern Study Notes (4)
/qq_51495235/article /details/115359246

23 design pattern study notes (5)
/qq_51495235/article/details/115359272

23 design pattern study notes (6)
/qq_51495235 /article/details/115359367

25. [Status Mode]

25.1 Definition and Characteristics of State Patterns

Definition of the State pattern: For stateful objects, complex “judgment logic” is extracted into different state objects, allowing the state object to change its behavior when its internal state changes.

The state pattern is an object behavioral pattern with the following main advantages.

  1. With a clear structure, the state pattern localizes the behavior related to a specific state into one state, and separates the behavior of different states, satisfying the “single responsibility principle”.
  2. Display state transitions to reduce interdependencies between objects. Introducing different states into separate objects makes state transitions more explicit and reduces interdependencies between objects.
  3. The responsibilities of the state class are clear, which is conducive to the expansion of the program. New states and transitions are easily added by defining new subclasses.

The main disadvantages of the state pattern are as follows.

  1. The use of the state pattern will inevitably increase the number of classes and objects in the system.
  2. The structure and implementation of the state pattern are complex, and if used improperly, it will lead to confusion in the program structure and code.
  3. The state mode does not support the open-closed principle very well. For the state mode that can switch states, adding a new state class requires modifying the source code responsible for state transition, otherwise it cannot switch to the new state, and modify a state class. The behavior also requires modifying the source code of the corresponding class.

25.2 Structure and Implementation of the State Pattern

[Example] The state of an elevator is controlled by buttons. An elevator has door-opening state, door-closing state, stop state, and running state. For each state change, it is possible to update processing based on other states. For example, if the elevator door is now in the running state, the door opening operation cannot be performed, and if the elevator door is in the stopped state, the door opening operation can be performed

public  interface  ILift  {
     //4 states of the elevator 
    //open state 
    public  final  static  int OPENING_STATE = 1 ;
     //close state 
    public  final  static  int CLOSING_STATE = 2 ;
     //running state 
    public  final  static  int RUNNING_STATE = 3 ;
     //stop state 
    public  final  static  int STOPPING_STATE = 4 ;

    //Set the state of the elevator 
    public  void  setState ( int state) ;

    //Elevator action 
    public  void  open () ;
     public  void  close () ;
     public  void  run () ;
     public  void  stop () ;
}

public class Lift implements ILift {
    private int state;

    @Override
    public void setState(int state) {
        this.state = state;
    }

    //Execute the closing action 
    @Override 
    public  void  close ()  {
         switch ( this .state) {
             case OPENING_STATE:
                System.out.println( "The elevator is closed..." ); //The elevator door can be closed only when the door is open. You can see 
                this .setState(CLOSING_STATE) corresponding to the elevator status table; //The elevator is in the closed state after the door is closed 
                break ;
             case CLOSING_STATE:
                 //do nothing //The door is already closed, can't close the door 
                break ;
             case RUNNING_STATE:
                 //do nothing //The elevator door is closed during running, can't close the door 
                break ;
             case STOPPING_STATE:
                 //do nothing // The elevator is also closed when it stops, and the door cannot be closed to 
                break ;
        }
    }

    //Execute the door opening action 
    @Override 
    public  void  open ()  {
         switch ( this .state) {
             case OPENING_STATE: //The door has been opened, can't open it again 
                //do nothing 
                break ;
             case CLOSING_STATE: //The door is closed, the door is open : 
                System.out.println( "The elevator door is open..." );
                 this .setState(OPENING_STATE);
                 break ;
             case RUNNING_STATE:
                 //do nothing The elevator cannot open the door when running 
                break ;
             case STOPPING_STATE:
                System.out.println( "The elevator door is open..." ); //The elevator has stopped, the door can be opened 
                this .setState(OPENING_STATE);
                 break ;
        }
    }

    //Execute the running action 
    @Override 
    public  void  run ()  {
         switch ( this .state) {
             case OPENING_STATE: //The elevator can't go without opening the door 
                //do nothing 
                break ;
             case CLOSING_STATE: //The door is closed, it can run 
                System.out.println( "The elevator is running..." );
                 this .setState(RUNNING_STATE); //It is running state now 
                break ;
             case RUNNING_STATE:
                 //do nothing is already running state 
                break ;
             case STOPPING_STATE:
                System.out.println( "The elevator is running..." );
                 this .setState(RUNNING_STATE);
                 break ;
        }
    }

    //Execute the stop action 
    @Override 
    public  void  stop ()  {
         switch ( this .state) {
             case OPENING_STATE: //The elevator that opens the door is already stopped (normally) 
                //do nothing 
                break ;
             case CLOSING_STATE: // Can only be stopped when the door is closed 
                System.out.println( "The elevator stopped..." );
                 this .setState(STOPPING_STATE);
                 break ;
             case RUNNING_STATE: //Of course it can be stopped when running 
                System.out.println( "The elevator stopped now..." );
                 this.setState(STOPPING_STATE);
                break;
            case STOPPING_STATE:
                //do nothing
                break;
        }
    }
}

public class Client {
    public static void main(String[] args) {
        Lift lift = new Lift();
        lift.setState(ILift.STOPPING_STATE); //The elevator is stopped 
        lift.open(); //Open the door 
        lift.close(); //Close the door 
        lift.run(); //Run 
        lift.stop(); // stop
    }
}

problem analysis

  • Using a lot of switch…case (and if…else) makes the program less readable.
  • Scalability is poor. If a new power-off state is added, we need to modify the above judgment logic

25.2.1 Structure of the State Pattern

  • Context role: Also known as context, it defines the interface required by the client program, maintains a current state, and delegates state-related operations to the current state object for processing.
  • Abstract state (State) role: define an interface to encapsulate the behavior corresponding to a specific state in the environment object.
  • Concrete State role: Implement the behavior corresponding to the abstract state.

25.2.2 Code Implementation

Relationship class diagram

LiftState

package com.zhuang.state.after;

/**
 * @Classname LiftState
 * @Description abstract state class
 * @Date 2021/3/31 10:50
 * @Created by dell
 */

public  abstract  class  LiftState  {
     //Define an environment role, that is, functional changes caused by changes in encapsulation state 
    protected Context context;

    public void setContext(Context context) {
        this.context = context;
    }

    //Elevator door open action 
    public  abstract  void  open () ;

    //Elevator door closing action 
    public  abstract  void  close () ;

    //Elevator running action 
    public  abstract  void  run () ;

    //Elevator stop action 
    public  abstract  void  stop () ;
}

Context

package com.zhuang.state.after;

/**
 * @Classname Context
 * @Description defines all elevator door states
 * @Date 2021/3/31 10:53
 * @Created by dell
 */

public  class  Context  {
     //Define all elevator states 
    //Open state, the elevator can only be closed at this time 
    public  final  static OpeningState OPENNING_STATE = new OpeningState();
     //Close state, at this time the elevator can run, stop and open the door 
    public  final  static ClosingState CLOSEING_STATE = new ClosingState();
     //Running state, the elevator can only stop at this time 
    public  final  static RunningState RUNNING_STATE = new RunningState();
     //Stopping state, the elevator can open the door and run at this time 
    public  final  static StoppingState STOPPING_STATE = new StoppingState();


    //Define a current elevator state 
    private LiftState liftState;

    public LiftState getLiftState() {
        return this.liftState;
    }

    public  void  setLiftState (LiftState liftState)  {
         //The current environment changes 
        this .liftState = liftState;
         //Notify the current environment to each implementation class 
        this .liftState.setContext( this );
    }

    public void open() {
        this.liftState.open();
    }

    public void close() {
        this.liftState.close();
    }

    public void run() {
        this.liftState.run();
    }

    public void stop() {
        this.liftState.stop();
    }
}

OpeningState

package com.zhuang.state.after;

/**
 * @Classname OpeningState
 * @Description on state
 * @Date 2021/3/31 10:51
 * @Created by dell
 */

public class OpeningState extends LiftState {


    //Of course it can be turned off, I just want to test the elevator door switch function 
    @Override 
    public  void  open ()  {
        System.out.println( "Elevator doors open..." );
    }

    @Override 
    public  void  close ()  {
         //State modification 
        super .context.setLiftState(Context.CLOSEING_STATE);
         //The action is delegated to CloseState to execute, that is, delegated to the ClosingState subclass to execute this action 
        super .context.getLiftState() .close();

    }

    //The elevator door can't be left open, do nothing here 
    @Override 
    public  void  run ()  {
         //do nothing
    }

    //The state of opening the door is already stopped 
    @Override 
    public  void  stop ()  {
         //do nothing
    }
}

ClosingState

package com.zhuang.state.after;

/**
 * @Classname ClosingState
 * @Description off state
 * @Date 2021/3/31 10:52
 * @Created by dell
 */

public  class  ClosingState  extends  LiftState  {
     @Override 
    //The elevator door is closed, this is the action to be implemented in the closed state 
    public  void  close ()  {
        System.out.println( "Elevator door closed..." );
    }

    //The elevator door is closed and then opened, just for fun, then this is allowed 
    @Override 
    public  void  open ()  {
         super .context.setLiftState(Context.OPENNING_STATE);
         super .context.open();
    }


    //It is normal to run when the elevator door is closed 
    @Override 
    public  void  run ()  {
         super .context.setLiftState(Context.RUNNING_STATE);
         super .context.run();
    }

    //The elevator door is closed, I will not press the floor 
    @Override 
    public  void  stop ()  {
         super .context.setLiftState(Context.STOPPING_STATE);
         super .context.stop();
    }
}

RunningState

package com.zhuang.state.after;

/**
 * @Classname RunningState
 * @Description running status
 * @Date 2021/3/31 10:52
 * @Created by dell
 */

public class RunningState extends LiftState {

    @Override 
    public  void  open ()  {
         //do nothing
    }

    @Override 
    public  void  close ()  {
         //do nothing
    }

    @Override
    public void run() {
        System.out.println( "The elevator is running..." );
    }

    @Override
    public void stop() {
        super.context.setLiftState(Context.OPENNING_STATE);
        super.context.stop();
    }
}

StoppingState

package com.zhuang.state.after;

/**
 * @Classname StoppingState
 * @Description stop status
 * @Date 2021/3/31 10:51
 * @Created by dell
 */

public class StoppingState extends LiftState {

    @Override 
    public  void  open ()  {
         //State modification 
        super .context.setLiftState(Context.OPENNING_STATE);
         //The action is delegated to CloseState to execute, that is, delegated to the ClosingState subclass to execute the action 
        super .context.getLiftState().open ();
    }

    @Override 
    public  void  close ()  {
         //State modification 
        super .context.setLiftState(Context.CLOSEING_STATE);
         //The action is delegated to CloseState to execute, that is, delegated to the ClosingState subclass to execute the action 
        super .context.getLiftState().close ();
    }

    @Override 
    public  void  run ()  {
         //State modification 
        super .context.setLiftState(Context.RUNNING_STATE);
         //The action is delegated to CloseState to execute, that is, delegated to the ClosingState subclass to execute the action 
        super .context.getLiftState().run ();
    }

    @Override
    public void stop() {
        System.out.println( "The elevator stopped..." );
    }
}

Client

package com.zhuang.state.after;

/**
 * @Classname Client
 * @Description state mode test class
 * @Date 2021/3/31 10:53
 * @Created by dell
 */

public  class  Client {
     public  static  void  main ( String[] args ) {
         //Open state 
        System. out .println( "Open state -->" );
        Context context1 = new Context();
        context1.setLiftState(new OpeningState());
        context1.open();
        context1.close();
        context1.run();
        context1.stop();

        System.out .println ( "=========================" );
         //Close the door System.out .println ( "Close the 
        door-- >" );
        Context context2 = new Context();
        context2.setLiftState(new ClosingState());
        context2.open();
        context2.close();
        context2.run();
        context2.stop();

        System.out .println ( "=========================" );
         //Running state System.out .println ( "Running state 
        -- >" );
        Context context3 = new Context();
        context3.setLiftState(new RunningState());
        context3.open();
        context3.close();
        context3.run();
        context3.stop();
System.out .println( "=========================" );
         //Stop state 
        System. 
        out .println ( " Stop state -- >" );
        Context context4 = new Context();
        context4.setLiftState(new StoppingState());
        context4.open();
        context4.close();
        context4.run();
        context4.stop();


    }
}

25.3 State Mode Application Scenario

  • The state pattern can be considered when the behavior of an object depends on its state, and it must change its behavior at runtime based on the state.
  • An operation contains a large branch structure, and these branches are determined by the state of the object.

26, strategy mode

26.1 Definition and Characteristics of Strategy Patterns

Definition of Strategy mode: This mode defines a series of algorithms and encapsulates each algorithm so that they can be replaced with each other, and changes in the algorithm will not affect customers who use the algorithm. The strategy pattern belongs to the object behavior pattern. It encapsulates the algorithm, separates the responsibility of using the algorithm from the implementation of the algorithm, and delegates the management of these algorithms to different objects.

The main advantages of the strategy pattern are as follows.

  1. Multiple conditional statements are not easy to maintain, and using the strategy pattern can avoid the use of multiple conditional statements, such as if…else statements, switch…case statements.
  2. The strategy pattern provides a series of reusable algorithm families. Proper use of inheritance can transfer the common code of the algorithm family to the parent class, thereby avoiding duplication of code.
  3. The strategy pattern can provide different implementations of the same behavior, and customers can choose different ones according to different time or space requirements.
  4. The strategy mode provides perfect support for the open-closed principle, and can flexibly add new algorithms without modifying the original code.
  5. The strategy pattern puts the use of the algorithm into the environment class, and moves the implementation of the algorithm into the concrete strategy class, realizing the separation of the two.

Its main disadvantages are as follows.

  1. The client must understand the difference between all policy algorithms in order to select the appropriate algorithm class at the right time.
  2. The strategy mode creates a lot of strategy classes, which increases the difficulty of maintenance.

26.2 Structure and Implementation of the Strategy Pattern

26.2.1 Structure of the Strategy Pattern

  1. Abstract strategy (Strategy) class: defines a public interface, various algorithms implement this interface in different ways, and environmental roles use this interface to call different algorithms, generally implemented by interfaces or abstract classes.
  2. Concrete Strategy class: implements the interface defined by the abstract strategy and provides specific algorithm implementation.
  3. Context class: Holds a reference to a policy class that is ultimately called by the client.

26.2.2 Code Implementation

Different promotions for different festivals

Relationship class diagram

Strategy

package com.zhuang.strategy;

/**
 * @Classname Strategy
 * @Description defines common interface
 * @Date 2021/3/31 15:29
 * @Created by dell
 */

public interface Strategy {
    void show();
}

StrategyA

package com.zhuang.strategy;

/**
 * @Classname StrategyA
 * @Description defines the specific promotions for each festival of the specific strategy role
 * @Date 2021/3/31 15:29
 * @Created by dell
 */

public class StrategyA implements Strategy {

    @Override
    public void show() {
        System.out.println( "A promotion buy one get one free" );
    }
}

StrategyB

package com.zhuang.strategy;

/**
 * @Classname StrategyB
 * @Description defines the specific promotions for each festival of the specific strategy role
 * @Date 2021/3/31 15:30
 * @Created by dell
 */

public class StrategyB implements Strategy {

    @Override
    public void show() {
        System.out.println( "B promotion over 100 minus 20" );
    }
}

StrategyC

package com.zhuang.strategy;

/**
 * @Classname StrategyC
 * @Description defines the specific promotions for each festival of the specific strategy role
 * @Date 2021/3/31 15:30
 * @Created by dell
 */

public class StrategyC implements Strategy {

    @Override
    public void show() {
        System.out.println( "C promotion over 500 yuan can be exchanged for small gifts" );
    }
}

SalesMan

package com.zhuang.strategy;

/**
 * @Classname SalesMan
 * @Description defines the context role used to connect the context to sell promotions to customers
 * @Date 2021/3/31 15:32
 * @Created by dell
 */

public class SalesMan {

    //Hold a reference to the abstract strategy role 
    private Strategy strategy;

    public SalesMan(Strategy strategy) {
        this.strategy = strategy;
    }

    public Strategy getStrategy() {
        return strategy;
    }

    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }

    //Show promotion 
    public  void  salesManShow ()  {
        strategy.show();
    }
}

Client

package com.zhuang.strategy;

/**
 * @Classname Client
 * @Description strategy pattern test class
 * @Date 2021/3/31 15:34
 * @Created by dell
 */

public class Client {
    public static void main(String[] args) {
        SalesMan salesMan = new SalesMan( new StrategyA());
         //Children's Day
        salesMan.salesManShow();

        System.out.println( "=======================" );
         //Labor Day 
        salesMan.setStrategy( new StrategyB());
        salesMan.salesManShow();

        System.out.println( "=======================" );
         //Dragon Boat Festival 
        salesMan.setStrategy( new StrategyC());
        salesMan.salesManShow();
    }
}

26.3 Application Scenarios of Strategy Mode

  • When a system needs to dynamically choose one of several algorithms, each algorithm can be encapsulated into a strategy class.
  • A class defines various behaviors, and these behaviors appear in the operation of the class in the form of multiple conditional statements that can be replaced by moving each conditional branch into their respective strategy class.
  • When the algorithms in the system are completely independent of each other, and the implementation details of specific algorithms are required to be hidden from customers.
  • When the system requires that clients using the algorithm should not know the data it operates on, the strategy pattern can be used to hide the data structures associated with the algorithm.
  • Multiple classes only differ in their performance behaviors. You can use the strategy pattern to dynamically select the specific behavior to be executed at runtime.

26.4 JDK source code analysis

Comparatorin strategy mode. There is a sort()method as follows:

public class Arrays{
    public static <T> void sort(T[] a, Comparator<? super T> c) {
        if (c == null) {
            sort(a);
        } else {
            if (LegacyMergeSort.userRequested)
                legacyMergeSort(a, c);
            else
                TimSort.sort(a, 0, a.length, c, null, 0, 0);
        }
    }
}

Arrays is an environment role class, the sort method can pass a new strategy to sort Arrays according to this strategy. Like the test class below.

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

        Integer[] data = { 12 , 2 , 3 , 2 , 4 , 5 , 1 };
         // implement descending sort 
        Arrays.sort(data, new Comparator<Integer>() {
             public  int  compare ( Integer o1, Integer o2 ) {
                 return o2 - o1;
            }
        });
        System.out.println(Arrays.toString(data)); //[12, 5, 4, 3, 2, 2, 1]
    }
}

Here we call the sort method of Arrays, the second parameter passed is the sub-implementation class object of the Comparator interface. So the Comparator acts as an abstract strategy role, while the concrete sub-implementation class acts as a concrete strategy role. Environment actor classes (Arrays) should hold a reference to the abstract strategy to call. So, does the sort method of the Arrays class use the compare()method ? Let us continue to look at the TimSort class sort()method , the code is as follows:

class TimSort<T> {
    static <T> void sort(T[] a, int lo, int hi, Comparator<? super T> c,
                         T[] work, int workBase, int workLen)  {
         assert c != null && a != null && no >= 0 && no <= this && this <= a.length;

        int nRemaining  = hi - lo;
        if (nRemaining < 2)
            return;  // Arrays of size 0 and 1 are always sorted

        // If array is small, do a "mini-TimSort" with no merges
        if (nRemaining < MIN_MERGE) {
            int initRunLen = countRunAndMakeAscending(a, lo, hi, c);
            binarySort(a, lo, hi, lo + initRunLen, c);
            return;
        }
        ...
    }   

    private static <T> int countRunAndMakeAscending(T[] a, int lo, int hi,Comparator<? super T> c) {
        assert lo < hi;
        int runHi = lo + 1;
        if (runHi == hi)
            return 1;

        // Find end of run, and reverse range if descending
        if (c.compare(a[runHi++], a[lo]) < 0) { // Descending
            while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) < 0)
                runHi++;
            reverseRange(a, lo, runHi);
        } else {                              // Ascending
            while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) >= 0)
                runHi++;
        }

        return runHi - lo;
    }
}

The code above ends up in countRunAndMakeAscending()this method. We can see that only the compare method is used, so when calling the Arrays.sort method, only the class object of the specific compare override method is passed, which is also a method that must be implemented by subclasses in the Comparator interface.

27. Chain of Responsibility Model

27.1 Definition and Characteristics of the Chain of Responsibility Model

Definition of the Chain of Responsibility pattern: In order to avoid coupling the request sender with multiple request handlers, all request handlers are connected into a chain through the previous object remembering the reference of its next object ; when a request occurs, the request can be passed down the chain until an object handles it.

Note: The Chain of Responsibility pattern is also called the Chain of Responsibility pattern.

In the chain of responsibility mode, the client only needs to send the request to the chain of responsibility, and does not need to care about the processing details of the request and the transfer process of the request, and the request will be automatically transferred. So the chain of responsibility decouples the sender of the request from the handler of the request.

The Chain of Responsibility pattern is an object behavioral pattern with the following main advantages.

  1. Reduced coupling between objects. This pattern makes it unnecessary for an object to know which object handles its request and the structure of the chain, and the sender and receiver do not need to have explicit information about each other.
  2. Enhanced system scalability. New request processing classes can be added as needed to satisfy the open-closed principle.
  3. Increased flexibility in assigning responsibilities to objects. When the workflow changes, members in the chain can be dynamically changed or their order can be mobilized, and responsibilities can be added or deleted dynamically.
  4. Chain of Responsibility simplifies the connection between objects. Each object only needs to keep a reference to its successor, not all other handlers, which avoids the use of numerous if or if…else statements.
  5. shared responsibility. Each class only needs to handle the work that it should handle, and pass the work that should not be handled to the next object to complete, clarify the scope of responsibility of each type, and comply with the single responsibility principle of the class.

Its main disadvantages are as follows.

  1. There is no guarantee that every request will be processed. Since a request has no explicit recipient, there is no guarantee that it will be processed, and the request may go all the way to the end of the chain without being processed.
  2. Compared with a longer responsibility chain, the processing of the request may involve multiple processing objects, and the system performance will be affected to a certain extent.
  3. The rationality of the establishment of the responsibility chain is guaranteed by the client, which increases the complexity of the client, and may cause system errors due to incorrect settings of the responsibility chain, such as cyclic calls.

27.2 Structure and Implementation of the Chain of Responsibility Pattern

27.2.1 Structure of the Chain of Responsibility Pattern

  1. Abstract handler (Handler) role: Define an interface for processing requests, including abstract processing methods and a subsequent connection.
  2. Concrete Handler role: Implement the processing method of the abstract handler, determine whether the request can be processed, if the request can be processed, process it, otherwise transfer the request to its successor.
  3. Client class (Client) role: Create a processing chain and submit a request to the specific handler object at the head of the chain. It does not care about the processing details and the delivery process of the request.

27.2.1 Code Implementation

Develop a leave process control system. Requests for leave of less than one day only require the approval of the team leader; requests for leave of 1 to 3 days require the approval of the department manager; requests for leave of 3 to 7 days require the approval of the general manager

Relationship class diagram

LeaveRequest

package com.zhuang.responsibility;

/**
 * @Classname LeaveRequest
 * @Description leave slip
 * @Date 2021/3/31 16:21
 * @Created by dell
 */

public  class  LeaveRequest  {
     //Name 
    private String name;
     // Leave days 
    private  int num;
     // Leave content 
    private String content;

    public LeaveRequest(String name, int num, String content) {
        this.name = name;
        this.num = num;
        this.content = content;
    }

    public String getName() {
        return name;
    }

    public  int  getNum ()  {
         return num;
    }

    public String getContent() {
        return content;
    }

}

Handler

package com.zhuang.responsibility;

/**
 * @Classname Handler
 * @Description describes the role of the class in one sentence
 * @Date 2021/3/31 16:23
 * @Created by dell
 */

public abstract class Handler {
    protected final static int NUM_ONE = 1;
    protected final static int NUM_THREE = 3;
    protected final static int NUM_SEVEN = 7;

    //The interval for the number of days of leave handled by the leader 
    private  int numStart;
     private  int numEnd;


    //There is also a leader 
    private Handler nextHandler on the leader;

    //Set the range of leave days 
    public  Handler ( int numStart)  {
         this .numStart = numStart;
    }

    //Set the range of leave days 
    public  Handler ( int numStart, int numEnd)  {
         this .numStart = numStart;
         this .numEnd = numEnd;
    }

    //Set the superior leader 
    public  void  setNextHandler (Handler nextHandler)  {
         this .nextHandler = nextHandler;
    }

    //Submit leave request 
    public  final  void  submit (LeaveRequest leaveRequest)  {
         if ( this .numStart == 0 ) {
             return ;
        }
        //The number of leave days reaches the leader's processing requirements 
        if (leaveRequest.getNum() >= this .numStart) {
             this .handleLeave(leaveRequest);

            //If there is still a superior and the number of days of leave exceeds the processing range of the current leader 
            if ( this .nextHandler != null && leaveRequest.getNum() > numEnd) {
                 //Continue to submit 
                this .nextHandler.submit(leaveRequest);
            } else {
                System.out.println( "Process ended!!!" );
            }
        }
    }

    //Leave processing method for leaders at all levels 
    protected  abstract  void  handleLeave (LeaveRequest leave) ;

}

GroupLeader

package com.zhuang.responsibility;

/**
 * @Classname GroupLeader
 * @Description group leader class
 * @Date 2021/3/31 16:33
 * @Created by dell
 */

public class GroupLeader extends Handler {
    public GroupLeader() {
        super(Handler.NUM_ONE, Handler.NUM_THREE);
    }

    @Override
    protected void handleLeave(LeaveRequest leave) {
        System.out.println( "Approved by the team leader: Agree!" );
    }
}

Manager

package com.zhuang.responsibility;

/**
 * @Classname Manager
 * @Description department manager class
 * @Date 2021/3/31 16:36
 * @Created by dell
 */

public  class  Manager  extends  Handler  {
     //3-7 days of fake 
    public  Manager ()  {
         super (Handler.NUM_THREE, Handler.NUM_SEVEN);
    }

    @Override
    protected void handleLeave(LeaveRequest leave) {
        System.out.println( "Approved by the department manager: Agree!" );
    }
}

GeneralManager

package com.zhuang.responsibility;

/**
 * @Classname GeneralManager
 * @Description general manager class
 * @Date 2021/3/31 16:38
 * @Created by dell
 */

public  class  GeneralManager  extends  Handler {
     //Fake more than 7 days 
    public  GeneralManager ()  {
         super (Handler.NUM_THREE, Handler.NUM_SEVEN);
    }

    @Override
    protected void handleLeave(LeaveRequest leave) {
        System.out.println( "Approved by the general manager: Agree!" );
    }
}

Client

package com.zhuang.responsibility;

/**
 * @Classname Client
 * @Description Chain of Responsibility Mode Test Class
 * @Date 2021/3/31 16:39
 * @Created by dell
 */

public  class  Client  {
     public  static  void  main (String[] args)  {
         // 
        LeaveRequest leave = new LeaveRequest( "Xiaozhuang" , 3 , "Traveling" );

        // Leaders 
        Manager manager = new Manager();
        GroupLeader groupLeader = new GroupLeader();
        GeneralManager generalManager = new GeneralManager();

        /*
        Team leader boss is manager manager boss is general manager
         */
        groupLeader.setNextHandler(manager);
        manager.setNextHandler(generalManager);

        //submit
        groupLeader.submit(leave);

    }
}

27.3 Application Scenarios of the Chain of Responsibility Pattern

  1. Multiple objects can handle a request, but which object handles the request is automatically determined at runtime.
  2. A set of objects can be dynamically specified to handle requests, or new handlers can be added.
  3. A request needs to be submitted to one of multiple handlers without explicitly specifying the request handler.

You may also like...

Leave a Reply

Your email address will not be published.