本文是我们名为“ Java设计模式 ”的学院课程的一部分。
在本课程中,您将深入研究大量的设计模式,并了解如何在Java中实现和利用它们。 您将了解模式如此重要的原因,并了解何时以及如何应用模式中的每一个。 在这里查看 !
目录
- 1.简介 2.什么是中介者模式 3.实施中介者模式 4.何时使用中介模式 5. JDK中的中介者模式 6.下载源代码
1.简介
当今世界在软件上运行。 现在,软件几乎可以在所有事物中运行,不仅可以在计算机中使用。 智能电视,移动电话,手表,洗衣机等具有用于操作机器的嵌入式软件。
一家大型电子公司要求您开发软件来操作其新的全自动洗衣机。 公司为您提供了硬件规格和机器的工作知识。 在规格中,他们为您提供了机器支持的不同洗涤程序。 他们想生产一种需要几乎0%的人机交互的全自动洗衣机。 用户只需要用水龙头连接机器即可供水,装载要洗涤的衣服,将机器的衣服类型设置为棉,丝绸或牛仔布等,在各自的托盘上提供洗涤剂和柔软剂,然后按开始按钮。
机器应足够智能,以根据需要将水倒入滚筒中。 它应根据衣物的类型通过打开加热器自行调节洗涤温度。 它应启动电动机并根据需要旋转滚筒,根据衣物需要冲洗,必要时使用去污剂,还应使用柔软剂。
作为面向对象的开发人员,您开始分析和分类对象,类及其关系。 让我们检查一些重要的类和系统的各个部分。 首先是Machine类,它有一个鼓。 鼓类,还有加热器,检查温度的传感器,电动机。 此外,机器还具有控制供水的阀,污垢清除剂,清洁剂和柔软剂。
这些类之间的关系非常复杂,并且关系也各不相同。 请注意,当前我们仅采用机器的高级抽象。 如果我们在设计时不考虑很多OOP原理和模式,那么初始设计将非常紧密地耦合在一起并且难以维护。 这是因为上述类应相互联系以完成工作。 例如,“机器”类应要求“阀门”类打开阀门,或者“电动机”应根据洗涤程序集(由机器中的衣物类型设置)以一定的rpm旋转滚筒。 某些类型的衣服需要柔软剂或去污剂,而其他类型则不需要,或者应根据衣服的类型设置温度。
如果我们允许类直接相互联系,也就是说,通过提供参考,设计将变得非常紧密并且难以维护。 在不影响另一个类别的情况下改变一个类别将变得非常困难。 更糟糕的是,根据不同的洗涤程序,类别之间的关系也有所不同,例如不同类型的衣服的温度不同。 因此,这些类将无法重用。 更糟糕的是,为了支持所有的清洗程序,我们需要在代码中放置诸如if-else之类的控制语句,这会使代码更加复杂且难以维护。
为了使这些对象彼此分离,我们需要一个介体,该介体将代表另一个对象接触该对象,从而在它们之间提供松散的耦合。 该对象仅需要了解介体,并对其执行操作。 中介者将对所需的基础对象执行操作,以完成工作。
中介者模式最适合于此,但是在实施它之前可以解决我们的问题。 首先让我们进一步了解介体设计模式。
2.什么是中介者模式
介体模式定义了一个对象,该对象封装了一组对象之间的交互方式。 介体通过防止对象之间显式地相互引用来促进松散耦合,并且它使您可以独立地更改它们之间的交互。
对象不是直接彼此交互,而是要求中介程序代表它们进行交互,这导致可重用性和松散耦合。 它封装了对象之间的交互并使它们彼此独立。 这使他们可以通过实现不同的介体以完全不同的方式改变与其他对象的交互。 介体有助于降低类的复杂性。 每个对象不再需要详细了解如何与其他对象交互。 对象之间的耦合从紧密和脆弱变为松散和敏捷。
在Mediator之前,类之间的交互可能看起来像这样,包含彼此的引用。
现在,实现介体后,类之间的交互看起来像这样,只包含对介体的引用。
只要您拥有紧密耦合的一组对象,介体设计模式就应该是您的首选。 如果一系列对象中的每个对象都必须了解其他对象的内部细节,并且维持这些关系成为问题,请考虑使用调解器。 使用调解器意味着交互代码只能驻留在一个地方,这使得维护更容易。 使用调解器可能会隐藏一个更严重的问题:如果多个对象紧密耦合,则封装可能有问题。 现在可能是重新考虑如何将程序分解为对象的时候了。
让我们看一下介体模式的更正式结构。
拥有调解员参考的班级称为同事。 调解员模式的主要参与者是:
- 介体:定义用于与同事对象进行通信的接口。
- ConcreteMediator:通过协调同事对象实现协作行为。 它还了解并维护其同事。
- 同事班:每个同事班都知道其Mediator对象。 只要有其他同事与之沟通,每个同事都会与其调解员进行沟通。
3.实施中介者模式
现在,我们将看到介体模式如何使洗衣机的设计更好,可重复使用,可维护且松耦合。
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
是充当通用介体的接口。 该接口包含一个对象调用到另一个对象的操作。
package com.javacodegeeks.patterns.mediatorpattern;public interface Colleague {public void setMediator(MachineMediator mediator);}
Colleague
界面有一种为具体同事的班级设置调解员的方法。
package com.javacodegeeks.patterns.mediatorpattern;public class Button implements Colleague {private MachineMediator mediator;@Overridepublic void setMediator(MachineMediator mediator){this.mediator = mediator;}public void press(){System.out.println("Button pressed.");mediator.start();}}
上面的Button
类是一个同事类,其中包含对调解器的引用。 用户按下按钮,该按钮调用此类的press()
方法,该按钮又调用具体介体类的start()
方法。 这start()
调解的方法调用start()
的机器类的代表的方法Button
类。
稍后,我们将看到中介者类的结构。 但是现在让我们首先看看其余的同事课堂。
package com.javacodegeeks.patterns.mediatorpattern;public class Machine implements Colleague {private MachineMediator mediator;@Overridepublic void setMediator(MachineMediator mediator){this.mediator = mediator;}public void start(){mediator.open();}public void wash(){mediator.wash();}
}
上面保留对中介程序的引用的Machine
类具有start()
方法,如上所述,该按钮由中介程序类在按下按钮时调用。 该方法具有介体的open()
方法,该介体又调用Valve
类的open()
方法以打开机器的阀门。
package com.javacodegeeks.patterns.mediatorpattern;public class Valve implements Colleague {private MachineMediator mediator;@Overridepublic 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()
方法,该调解器将调用此类的方法。
关闭阀门后,它会打开加热器,但再次调用调解员的方法,而不是直接调用加热器的方法。
package com.javacodegeeks.patterns.mediatorpattern;public class Heater implements Colleague {private MachineMediator mediator;@Overridepublic 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()
方法。 通过调解器检查温度并关闭加热器。
关闭后,它将通过中介程序调用Machine类的wash()
方法以开始清洗。
如该公司所述,洗衣机具有一套洗涤程序,该软件应支持所有这些程序。 以下介体实际上是机器的清洗程序之一。 下面的介体被设置为棉花的洗涤程序,因此相应地设置了诸如温度,转鼓纺丝速度,去污水平等参数。 我们可以在不更改现有同事类别的情况下为不同的清洗程序使用不同的介体,从而提供松散的耦合性和可重用性。 所有这些同事课程都可以与其他洗衣机程序一起重复使用。
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.........................");}@Overridepublic void start() {machine.start();}@Overridepublic void wash() {motor.startMotor();motor.rotateDrum(700);System.out.println("Adding detergent");soilRemoval.low();System.out.println("Adding softener");}@Overridepublic void open() {valve.open();}@Overridepublic void closed() {valve.closed();}@Overridepublic void on() {heater.on(40);}@Overridepublic void off() {heater.off();}@Overridepublic boolean checkTemperature(int temp) {return sensor.checkTemperature(temp);}}
CottonMediator
类实现MachineMediator
接口并提供所需的方法。 这些方法是同事对象为了完成工作而执行的操作。 上面的调解器类仅代表另一个同事对象调用同事对象的方法即可实现此目的。
还有其他一些支持类:
package com.javacodegeeks.patterns.mediatorpattern;public class Sensor {public boolean checkTemperature(int temp){System.out.println("Temperature reached "+temp+" *C");return true;}}
Heater
使用Sensor
类别检查温度。
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
类。
为了感受到Mediator Pattern的优势和力量,让我们以另一个用作牛仔布洗涤程序的Mediator为例。 现在,我们只需要创建一个新的介体并在其中设置洗牛仔布的规则即可:诸如温度,鼓旋转的速度,是否需要软化剂,除污水平等规则。无需更改现有结构中的任何内容。 不需要诸如“ if-else”之类的条件语句,这会增加复杂性。
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.........................");}@Overridepublic void start() {machine.start();}@Overridepublic void wash() {motor.startMotor();motor.rotateDrum(1400);System.out.println("Adding detergent");soilRemoval.medium();System.out.println("Adding softener");}@Overridepublic void open() {valve.open();}@Overridepublic void closed() {valve.closed();}@Overridepublic void on() {heater.on(30);}@Overridepublic void off() {heater.off();}@Overridepublic boolean checkTemperature(int temp) {return sensor.checkTemperature(temp);}}
您可以清楚地看到两个调解器类之间的差异。 温度不同,纺丝速度也不同,牛仔布洗涤不需要软化剂。
现在测试这些介体。
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();}}
上面的程序将具有以下输出:
.........................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.何时使用中介模式
- 一组对象以定义明确但复杂的方式进行通信。 由此产生的相互依存关系是无结构的,难以理解。
- 重用一个对象很困难,因为它引用了许多其他对象并与之通信。
- 在多个类之间分布的行为应该是可自定义的,而无需大量子类化。
5. JDK中的中介者模式
JDK中几乎所有地方都使用了设计模式。 以下是JDK中介体模式的用法。
-
java.util.concurrent.ScheduledExecutorService
(所有scheduleXXX()
方法) -
java.util.concurrent.ExecutorService
(invokeXXX()
和invokeXXX()
submit()
方法) -
java.util.concurrent.Executor#execute()
-
java.util.Timer
(所有scheduleXXX()
方法) -
java.lang.reflect.Method#invoke()
6.下载源代码
这是“调解员模式”的一课。 您可以在此处下载源代码: MediatorPattern-Project
翻译自: https://www.javacodegeeks.com/2015/09/mediator-design-pattern.html