[design mode from introduction to mastery] 17 - intermediary mode

Posted by inrealtime on Tue, 11 Jan 2022 15:12:12 +0100

Note source: Shang Silicon Valley Java design pattern (illustration + framework source code analysis)

Intermediary model

1. Smart home management issues

Smart home project:

  • 1) Smart home includes various devices, alarm clock, coffee machine, TV, curtain, etc

  • 2) When the host wants to watch TV, various devices can work together to automatically complete the preparation for watching TV. For example, the process is as follows:

    The alarm goes off = > the coffee machine starts making coffee = > the curtains fall automatically = > the TV starts playing

Traditional solutions solve the problem of intelligent home management

Analysis of traditional methods

  • 1) When there are many state changes of electrical objects, the calling relationship between them will be more complex
  • 2) All electrical objects are connected with each other. You have me and I have you, which is not conducive to loose coupling
  • 3) Messages (parameters) passed between electrical objects are easy to be confused
  • 4) When a new electrical object is added to the system or the execution process is changed, the maintainability and scalability of the code are not ideal → consider the intermediary mode

2. Intermediary model

  • 1) The Mediator Pattern encapsulates a series of object interactions with a mediation object. Mediators make objects do not need to explicitly refer to each other, so that they are loosely coupled, and their interaction can be changed independently
  • 2) The mediator pattern is a behavioral pattern that makes the code easy to maintain
  • 3) For example, in MVC mode, C (Controller) is the mediator of M (Model model) and V (View), and acts as an intermediary in front and back-end interaction

Schematic class diagram

Intermediary model roles and responsibilities

  • Mediator: defines the interface from colleague object to mediator object
  • ConcreteMediator [concrete mediator object]: to implement the abstract mediator method, you need to know all specific colleague classes, that is, manage HashMap in a collection, accept a colleague object message and complete the corresponding task
  • Collague [Abstract Colleague class]
  • ConcreteColleague: there are many colleagues who only know their own behavior and do not know the behavior (Methods) of other colleagues, but they all rely on the intermediary object

3. Intermediary model to solve the problem of intelligent home management

UML class diagram

Operation flow of intelligent home management

  • 1) Create a concrete mediator object
  • 2) Create various colleague objects, such as Alarm, coffee machine, TV
  • 3) When creating a colleague class object, it is directly added to the colleguemap through the constructor
  • 4) The colleague class object can call sendMessage and will eventually call the getMessage method of ConcreteMediator
  • 5) getMessage will coordinate and call other colleague objects to complete the task according to the message sent by the received colleague object
  • 6) You can see that getMessage is the core method to complete the corresponding tasks

Core code

Abstract mediator

public abstract class Mediator {
    public abstract void registerColleague(Colleague colleague);

    public abstract void getMsg(Integer state, String name);

    public abstract void sendMsg();
}

Abstract colleague class

public abstract class Colleague {
    private Mediator mediator;

    public Colleague(Mediator mediator) {
        this.mediator = mediator;
    }

    public Mediator getMediator() {
        return this.mediator;
    }

    public void sendMsg(Integer state) {
        this.getMediator().getMsg(state, this.getClass().getSimpleName());
    }
}

Specific colleagues

/**
 * alarm clock
 */
public class Alarm extends Colleague {
    public Alarm(Mediator mediator) {
        super(mediator);
        this.getMediator().registerColleague(this);
    }

    /**
     * The alarm goes off
     */
    public void openAlarm() {
        System.out.println(">>>The alarm goes off");
        try {
            //Analog alarm time
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        sendMsg(1);
    }

    /**
     * Alarm off
     */
    public void closeAlarm() {
        System.out.println(">>>Alarm off");
        sendMsg(0);
    }
}
/**
 * Coffee machine
 */
public class CoffeeMachine extends Colleague {
    public CoffeeMachine(Mediator mediator) {
        super(mediator);
        this.getMediator().registerColleague(this);
    }

    /**
     * Cook Coffee
     */
    public void makeCoffee() {
        System.out.println(">>>Making coffee...");
        sendMsg(0);
        try {
            //Simulated coffee making time
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * The coffee is over
     */
    public void completeCoffee() {
        System.out.println(">>>The coffee is ready");
        sendMsg(1);
    }
}
/**
 * window curtains
 */
public class Curtain extends Colleague {
    public Curtain(Mediator mediator) {
        super(mediator);
        this.getMediator().registerColleague(this);
    }

    /**
     * Pull up the curtains
     */
    public void upCurtain() {
        System.out.println(">>>Pull up the curtains...");
        sendMsg(1);
        try {
            //Simulating the time-consuming of pulling up curtains
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * Pull down the curtains
     */
    public void downCurtain() {
        System.out.println(">>>Pull down the curtains...");
        sendMsg(0);
        try {
            //Simulating the time-consuming of pulling down the curtain
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
/**
 * Television
 */
public class TV extends Colleague {
    public TV(Mediator mediator) {
        super(mediator);
        this.getMediator().registerColleague(this);
    }

    /**
     * Turn on the TV
     */
    public void openTV() {
        System.out.println(">>>Turn on the TV...");
        sendMsg(1);
    }

    /**
     * Turn off the TV
     */
    public void closeTV() {
        System.out.println(">>>Turn off the TV...");
        sendMsg(0);
    }

    /**
     * Switch channels
     */
    public void switchChannel(Integer state) {
        System.out.println(">>>Switch channels:" + state);
        sendMsg(state);
        try {
            //Analog TV viewing takes time
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Specific intermediary

public class ConcreteMediator extends Mediator {
    private Map<String, Colleague> colleagueMap;

    public ConcreteMediator() {
        this.colleagueMap = new HashMap<>();
    }

    @Override
    public void registerColleague(Colleague colleague) {
        colleagueMap.put(colleague.getClass().getSimpleName(), colleague);
    }

    @Override
    public void getMsg(Integer state, String name) {
        Colleague colleague = colleagueMap.get(name);
        if (colleague instanceof Alarm) {
            dealAlarm(state);
        } else if (colleague instanceof CoffeeMachine) {
            dealCoffeeMachine(state);
        } else if (colleague instanceof Curtain) {
            dealCurtain(state);
        } else if (colleague instanceof TV) {
            dealTV(state);
        }
    }

    /**
     * Operation after the alarm sounds
     *
     * @param state
     */
    private void dealAlarm(Integer state) {
        if (Integer.valueOf(1).equals(state)) {
            ((Alarm) colleagueMap.get(Alarm.class.getSimpleName())).closeAlarm();
            ((CoffeeMachine) colleagueMap.get(CoffeeMachine.class.getSimpleName())).makeCoffee();
        }
    }

    /**
     * Operate the coffee machine after making coffee
     *
     * @param state
     */
    private void dealCoffeeMachine(Integer state) {
        if (Integer.valueOf(1).equals(state)) {
            ((Curtain) colleagueMap.get(Curtain.class.getSimpleName())).downCurtain();
        }
    }

    /**
     * Operation after curtain falls
     *
     * @param state
     */
    private void dealCurtain(Integer state) {
        if (Integer.valueOf(0).equals(state)) {
            TV tv = (TV) colleagueMap.get(TV.class.getSimpleName());
            tv.openTV();
            tv.switchChannel(101);
        }
    }

    /**
     * Operation after TV off
     *
     * @param state
     */
    private void dealTV(Integer state) {
        if (Integer.valueOf(0).equals(state)) {
            ((Curtain) colleagueMap.get(Curtain.class.getSimpleName())).upCurtain();
        }
    }

    @Override
    public void sendMsg() {
        // Do Nothing...
    }
}

Test code

//Create mediator
Mediator mediator = new ConcreteMediator();

//Create each colleague class and add it to the Map object of the Mediator mediator
Alarm alarm = new Alarm(mediator);
CoffeeMachine coffeeMachine = new CoffeeMachine(mediator);
Curtain curtain = new Curtain(mediator);
TV tv = new TV(mediator);

//The alarm clock rings
alarm.openAlarm();
coffeeMachine.completeCoffee();
tv.closeTV();

//>>>The alarm goes off
//>>>Alarm off
//>>>Making coffee
//>>>The coffee is ready
//>>>Pull down the curtains
//>>>Turn on the TV
//>>>Switching channels: 101
//>>>Turn off TV
//>>>Pull up the curtains

4. Considerations and details of the mediator model

advantage

  • 1) When multiple classes are coupled with each other, a mesh structure will be formed. The mediator pattern is used to separate the mesh structure into a star structure for decoupling

  • 2) Reduce the dependency between classes and reduce the coupling, which is in line with the Demeter principle

shortcoming

  • 3) Intermediaries bear more responsibilities. Once the intermediaries have problems, the whole system will be affected

  • 4) If not designed properly, the mediator object itself becomes too complex, which should be paid special attention to in practical use

Topics: Design Pattern