Статьи

Пример шаблона дизайна посредника

Эта статья является частью нашего курса Академии под названием « Шаблоны проектирования Java» .

В этом курсе вы изучите огромное количество шаблонов проектирования и увидите, как они реализуются и используются в Java. Вы поймете причины, почему шаблоны так важны, и узнаете, когда и как применять каждый из них. Проверьте это здесь !

1. Введение

Сегодняшний мир работает на программном обеспечении. Программное обеспечение теперь работает практически во всем, оно используется не только в компьютерах. Смарт-телевидение, мобильные телефоны, наручные часы, стиральные машины и т. Д. Имеют встроенное программное обеспечение, которое управляет машиной.

Крупная электронная компания попросила вас разработать программное обеспечение для своей новой полностью автоматической стиральной машины. Компания предоставила вам технические характеристики оборудования и рабочие знания машины. В спецификации они предоставили вам различные программы стирки, которые поддерживает машина. Они хотят производить полностью автоматическую стиральную машину, которая потребует почти 0% взаимодействия с человеком. Пользователь должен только подключить машину к крану для подачи воды, загрузить одежду для стирки, установить тип одежды в машине, например, хлопок, шелк или джинсовые ткани и т. Д., Предоставить моющее средство и смягчитель для соответствующих лотков и нажать кнопка запуска.

Машина должна быть достаточно умной, чтобы заполнить водой в барабане столько, сколько потребуется. Следует самостоятельно отрегулировать температуру стирки, включив обогреватель, в соответствии с типом одежды в нем. Он должен запустить двигатель и вращать барабан столько, сколько требуется, промыть в соответствии с потребностями одежды, использовать удаление почвы при необходимости, а также смягчитель.

Как объектно-ориентированный разработчик, вы начали анализировать и классифицировать объекты, классы и их отношения. Давайте проверим некоторые важные классы и части системы. Прежде всего, класс Machine, в котором есть барабан. Таким образом, класс барабана, но также нагреватель, датчик для проверки температуры, двигатель. Кроме того, машина также имеет клапан для контроля подачи воды, удаления загрязнений, моющих средств и умягчителя.

Эти классы имеют очень сложные отношения друг с другом, и отношения также различаются. Обращаем ваше внимание, что в настоящее время мы рассматриваем только высокий уровень абстракции машины. Если мы попытаемся разработать его, не помня о принципах и шаблонах ООП, то первоначальный проект будет очень тесно связан и его трудно поддерживать. Это потому, что вышеупомянутые классы должны связаться друг с другом, чтобы выполнить работу. Как, например, класс Machine должен попросить класс Valve открыть клапан, или двигатель должен вращать барабан при определенных оборотах в соответствии с установленной программой стирки (которая определяется типом одежды в машине). Некоторые типы одежды требуют смягчения или удаления загрязнений, в то время как другие этого не делают, или температуру следует устанавливать в соответствии с типом одежды.

Если мы позволим классам связываться друг с другом напрямую, то есть, предоставляя ссылку, дизайн станет очень тесно связанным и сложным в обслуживании. Было бы очень трудно изменить один класс, не затрагивая другой. Что еще хуже, отношения между классами различаются, в зависимости от разных программ стирки, например, разные температуры для разных типов одежды. Таким образом, эти классы не смогут быть повторно использованы. Хуже того, чтобы поддерживать все программы стирки, нам нужно поместить в код управляющие операторы типа if-else, что сделало бы код еще более сложным и трудным в обслуживании.

Чтобы отделить эти объекты друг от друга, нам нужен посредник, который будет связываться с объектом от имени другого объекта, что обеспечивает слабую связь между ними. Объекту нужно только знать о посреднике и выполнять над ним операции. Посредник будет выполнять операции с требуемым базовым объектом, чтобы выполнить работу.

Шаблон Mediator лучше всего подходит для этого, но прежде чем применять его для решения нашей проблемы. Давайте сначала узнаем больше о модели проектирования посредника.

2. Что такое образец посредника

Шаблон посредника определяет объект, который инкапсулирует, как взаимодействует набор объектов. Посредник способствует слабой связи, не позволяя объектам явно ссылаться друг на друга, и позволяет независимо изменять их взаимодействие.

Вместо того, чтобы взаимодействовать напрямую друг с другом, объекты просят посредника взаимодействовать от их имени, что приводит к повторному использованию и слабой связи. Он инкапсулирует взаимодействие между объектами и делает их независимыми друг от друга. Это позволяет им совершенно по-разному изменять свое взаимодействие с другими объектами путем реализации другого посредника. Посредник помогает уменьшить сложность занятий. Каждый объект больше не должен знать подробно о том, как взаимодействовать с другими объектами. Связь между объектами меняется от жесткой и хрупкой до свободной и подвижной.

До Посредника взаимодействие между классами могло бы выглядеть следующим образом, содержащим ссылки друг на друга.

фигура 1

фигура 1

Теперь после реализации медиатора взаимодействие между классами выглядит следующим образом, только содержит ссылку на медиатора.

фигура 2

фигура 2

Шаблон проектирования Mediator должен быть вашим первым выбором в любое время, когда у вас есть набор тесно связанных объектов. Если каждый из ряда объектов должен знать внутренние детали других объектов, и поддержание этих отношений становится проблемой, подумайте о Посреднике. Использование посредника означает, что код взаимодействия должен находиться только в одном месте, и это облегчает поддержку. Использование посредника может скрыть более серьезную проблему: если у вас есть несколько тесно связанных объектов, ваша инкапсуляция может быть повреждена. Возможно, пришло время переосмыслить, как вы разбили свою программу на объекты.

Давайте посмотрим на более формальную структуру паттерна посредника.

Рисунок 3

Рисунок 3

Класс, который содержит ссылку на посредника, называют коллегами. Основными участниками модели посредника являются:

  1. Посредник: Определяет интерфейс для связи с объектами Коллеги.
  2. ConcreteMediator: реализует совместное поведение, координируя объекты коллег. Он также знает и поддерживает своих коллег.
  3. Классы коллег: каждый класс коллеги знает свой объект-посредник. Каждый коллега общается со своим посредником всякий раз, когда он в противном случае общался бы с другим коллегой.

3. Реализация паттерна посредника

Теперь мы увидим, как шаблон Mediator Pattern сделает конструкцию стиральной машины лучше, многоразовой, ремонтопригодной и слабо связанной.

01
02
03
04
05
06
07
08
09
10
11
12
13
package com.javacodegeeks.patterns.mediatorpattern;
 
public interface MachineMediator {
     
    public void start();
    public void wash();
    public void open();
    public void closed();
    public void on();
    public void off();
    public boolean checkTemperature(int temp);
 
}

MachineMediator — это интерфейс, который действует как универсальный посредник. Интерфейс содержит операции вызова одного объекта другому.

1
2
3
4
5
6
7
package com.javacodegeeks.patterns.mediatorpattern;
 
public interface Colleague {
     
    public void setMediator(MachineMediator mediator);
 
}

Интерфейс « Colleague имеет один метод для установки посредника для класса конкретного коллеги.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
package com.javacodegeeks.patterns.mediatorpattern;
 
public class Button implements Colleague {
     
    private MachineMediator mediator;
     
    @Override
    public void setMediator(MachineMediator mediator){
        this.mediator = mediator;
    }
     
    public void press(){
        System.out.println("Button pressed.");
        mediator.start();
    }
 
}

Приведенный выше класс Button является классом коллег, который содержит ссылку на посредника. Пользователь нажимает кнопку, которая вызывает метод press() этого класса, который, в свою очередь, вызывает метод start() конкретного класса-посредника. Этот метод start() посредника вызывает метод start() машинного класса от имени класса Button .

Позже мы увидим структуру класса посредника. Но теперь давайте сначала посмотрим на остальные классы коллег.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
package com.javacodegeeks.patterns.mediatorpattern;
 
public class Machine implements Colleague {
 
    private MachineMediator mediator;
     
    @Override
    public void setMediator(MachineMediator mediator){
        this.mediator = mediator;
    }
     
    public void start(){
        mediator.open();
    }
     
    public void wash(){
        mediator.wash();
    }
}

Вышеупомянутый класс Machine который содержит ссылку на медиатор, имеет метод start() который вызывается при нажатии кнопки классом медиатора, как обсуждалось выше. У метода есть метод open() посредника, который, в свою очередь, вызывает метод open() класса Valve , чтобы открыть клапан машины.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.javacodegeeks.patterns.mediatorpattern;
 
public class Valve implements Colleague {
 
    private MachineMediator mediator;
     
    @Override
    public void setMediator(MachineMediator mediator){
        this.mediator = mediator;
    }
     
    public void open(){
        System.out.println("Valve is opened...");
        System.out.println("Filling water...");
        mediator.closed();
    }
     
    public void closed(){
        System.out.println("Valve is closed...");
        mediator.on();
    }
}

Класс Valve имеет два метода: метод open() который вызывается для открытия клапана, а когда вода заполняется, он называется методом closed() . Но обратите внимание, что он не вызывает метод closed() напрямую, он вызывает метод closed() посредника, который вызывает метод этого класса.

При закрытии клапана он включает нагреватель, но снова, вызывая метод посредника вместо прямого вызова метода нагревателя.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.javacodegeeks.patterns.mediatorpattern;
 
public class Heater implements Colleague {
 
    private MachineMediator mediator;
     
    @Override
    public void setMediator(MachineMediator mediator){
        this.mediator = mediator;
    }
    public void on(int temp){
        System.out.println("Heater is on...");
        if(mediator.checkTemperature(temp)){
            System.out.println("Temperature is set to "+temp);
            mediator.off();
        }
    }
     
    public void off(){
        System.out.println("Heater is off...");
        mediator.wash();
    }
}

Метод on() нагревателя включает нагреватель и устанавливает температуру по мере необходимости. Он также проверяет, достигнута ли температура в соответствии с требованиями, off() метод. Проверка температуры и выключение нагревателя осуществляется через посредник.

После выключения через посредник вызывается метод wash() класса Machine для запуска стирки.

Как заявили в компании, стиральная машина имеет набор программ стирки, и программное обеспечение должно поддерживать все эти программы. Приведенный ниже медиатор фактически является одной из программ стирки для машины. Приведенный ниже медиатор установлен в качестве программы стирки для хлопка, поэтому такие параметры, как температура, скорость вращения барабана, уровень удаления почвы и т. Д., Устанавливаются соответствующим образом. У нас могут быть разные посредники для разных программ стирки без изменения существующих классов коллег и, таким образом, обеспечения слабой связи и возможности повторного использования. Все эти классы коллег могут быть повторно использованы с другими программами мойки машины.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package com.javacodegeeks.patterns.mediatorpattern;
 
public class CottonMediator implements MachineMediator{
     
    private final Machine machine;
    private final Heater heater;
    private final Motor motor;
    private final Sensor sensor;
    private final SoilRemoval soilRemoval;
    private final Valve valve;
     
    public CottonMediator(Machine machine,Heater heater,Motor motor,Sensor sensor,SoilRemoval soilRemoval,Valve valve){
        this.machine = machine;
        this.heater = heater;
        this.motor = motor;
        this.sensor = sensor;
        this.soilRemoval = soilRemoval;
        this.valve = valve;
         
        System.out.println(".........................Setting up for COTTON program.........................");
    }
    @Override
    public void start() {
        machine.start();
    }
 
    @Override
    public void wash() {
        motor.startMotor();
        motor.rotateDrum(700);
        System.out.println("Adding detergent");
        soilRemoval.low();
        System.out.println("Adding softener");
    }
 
    @Override
    public void open() {
        valve.open();
    }
 
    @Override
    public void closed() {
        valve.closed();
    }
 
    @Override
    public void on() {
        heater.on(40);
    }
 
    @Override
    public void off() {
        heater.off();
    }
 
    @Override
    public boolean checkTemperature(int temp) {
        return sensor.checkTemperature(temp);
    }
 
}

Класс CottonMediator реализует интерфейс CottonMediator и предоставляет необходимые методы. Эти методы являются операциями, которые выполняются объектами коллеги, чтобы выполнить работу. Вышеупомянутый класс-посредник просто вызывает метод объекта коллеги от имени другого объекта коллеги для достижения этой цели.

Есть также некоторые другие вспомогательные классы:

01
02
03
04
05
06
07
08
09
10
package com.javacodegeeks.patterns.mediatorpattern;
 
public class Sensor {
     
    public boolean checkTemperature(int temp){
        System.out.println("Temperature reached "+temp+" *C");
        return true;
    }
 
}

Класс Sensor используется Heater для проверки температуры.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
package com.javacodegeeks.patterns.mediatorpattern;
 
public class SoilRemoval {
 
    public void low(){
        System.out.println("Setting Soil Removal to low");
    }
     
    public void medium(){
        System.out.println("Setting Soil Removal to medium");
    }
     
    public void high(){
        System.out.println("Setting Soil Removal to high");
    }
}

Класс SoilRemoval используется классом Machine .

Чтобы ощутить преимущества и силу шаблона «Посредник», давайте возьмем другого посредника, который используется в качестве программы стирки джинсовой ткани. Теперь нам просто нужно создать новый медиатор и установить в нем правила для стирки джинсовой ткани: правила, такие как температура и скорость вращения барабана, требуется ли смягчитель или нет, уровень удаления загрязнений и т. Д. Не нужно ничего менять в существующей структуре. Не требуется никаких условных операторов, таких как «if-else», что увеличит сложность.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package com.javacodegeeks.patterns.mediatorpattern;
 
public class DenimMediator implements MachineMediator{
 
    private final Machine machine;
    private final Heater heater;
    private final Motor motor;
    private final Sensor sensor;
    private final SoilRemoval soilRemoval;
    private final Valve valve;
 
    public DenimMediator(Machine machine,Heater heater,Motor motor,Sensor sensor,SoilRemoval soilRemoval,Valve valve){
        this.machine = machine;
        this.heater = heater;
        this.motor = motor;
        this.sensor = sensor;
        this.soilRemoval = soilRemoval;
        this.valve = valve;
 
        System.out.println(".........................Setting up for DENIM program.........................");
    }
    @Override
    public void start() {
        machine.start();
    }
 
    @Override
    public void wash() {
        motor.startMotor();
        motor.rotateDrum(1400);
        System.out.println("Adding detergent");
        soilRemoval.medium();
        System.out.println("Adding softener");
    }
 
    @Override
    public void open() {
        valve.open();
    }
 
    @Override
    public void closed() {
        valve.closed();
    }
 
    @Override
    public void on() {
        heater.on(30);
    }
 
    @Override
    public void off() {
        heater.off();
    }
 
    @Override
    public boolean checkTemperature(int temp) {
        return sensor.checkTemperature(temp);
    }
     
}

Вы можете ясно видеть различия между двумя классами-посредниками. Температура различна, скорость отжима также различна, и для стирки денима не требуется смягчитель.

Теперь проверьте эти посредники.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.javacodegeeks.patterns.mediatorpattern;
 
public class TestMediator {
 
    public static void main(String[] args) {
        MachineMediator mediator = null;
        Sensor sensor = new Sensor();
        SoilRemoval soilRemoval = new SoilRemoval();
        Motor motor = new Motor();
        Machine machine = new Machine();
        Heater heater = new Heater();
        Valve valve = new Valve();
        Button button = new Button();
         
        mediator = new CottonMediator(machine, heater, motor, sensor, soilRemoval, valve);
         
        button.setMediator(mediator);
        machine.setMediator(mediator);
        heater.setMediator(mediator);
        valve.setMediator(mediator);
         
        button.press();
         
        System.out.println("******************************************************************************");
         
        mediator = new DenimMediator(machine, heater, motor, sensor, soilRemoval, valve);
         
        button.setMediator(mediator);
        machine.setMediator(mediator);
        heater.setMediator(mediator);
        valve.setMediator(mediator);
         
        button.press();
    }
 
}

Вышеуказанная программа будет иметь следующий результат:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
.........................Setting up for COTTON program.........................
Button pressed.
Valve is opened...
Filling water...
Valve is closed...
Heater is on...
Temperature reached 40 *C
Temperature is set to 40
Heater is off...
Start motor...
Rotating drum at 700 rpm.
Adding detergent
Setting Soil Removal to low
Adding softener
******************************************************************************
.........................Setting up for DENIM program.........................
Button pressed.
Valve is opened...
Filling water...
Valve is closed...
Heater is on...
Temperature reached 30 *C
Temperature is set to 30
Heater is off...
Start motor...
Rotating drum at 1400 rpm.
Adding detergent
Setting Soil Removal to medium
No softener is required

В вышеприведенном классе мы создали необходимые объекты, посредники (или мы можем сказать разные программы стирки), затем мы установили программы стирки для коллег и наоборот, и мы вызвали метод start() для объекта кнопки, чтобы запустить машину. Все остальное делается автоматически, без участия человека.

Обратите внимание, что для работы с другой программой стирки устанавливается другой медиатор, а остальное остается прежним. Вы можете ясно увидеть отличия от вывода.

4. Когда использовать шаблон посредника

  1. Набор объектов общается четко определенными, но сложными способами. Получающиеся взаимозависимости неструктурированы и трудны для понимания.
  2. Повторное использование объекта является сложным, поскольку оно ссылается на многие другие объекты и взаимодействует с ними.
  3. Поведение, которое распределяется между несколькими классами, должно быть настраиваемым без большого количества подклассов.

5. Образец посредника в JDK

Шаблоны проектирования используются почти везде в JDK. Ниже приведены примеры использования модели посредника в JDK.

  1. java.util.concurrent.ScheduledExecutorService (все методы scheduleXXX() )
  2. java.util.concurrent.ExecutorService ( invokeXXX() и submit() )
  3. java.util.concurrent.Executor#execute()
  4. java.util.Timer (все методы scheduleXXX() )
  5. java.lang.reflect.Method#invoke()

6. Загрузите исходный код

Это был урок по Паттерну Посредника. Вы можете скачать исходный код здесь: MediatorPattern-Project