中介模式屬於行為型設計模式,可以將原本難以理解的網狀結構轉換成了相對加單的星型結構,主要用來降低多個對象和類之間的通信複雜性。 ...
簡介
中介設計模式(Mediator Design Pattern)定義了一個單獨的(中介)對象,來封裝一組對象之間的交互。
如果對象之間存在大量的相互關聯和調用,若有一個對象發生變化,則需要跟蹤和該對象的其他所有對象,併進行適當處理。
而中介模式將這些對象之間的交互委派給中介對象交互,來避免對象之間直接交互,使其耦合鬆散。
典型實現
首先,定義一個抽象中介者介面,該介面用於與各對象之間進行通信。其代碼示例如下:
public abstract class Mediator {
// 維持所有同事對象的引用
protected ArrayList<Colleague> colleagues;
// 註冊方法,用於增加同事對象
public void register(Colleague colleague) {
colleagues.add(colleague);
}
// 聲明抽象的業務方法
public abstract void operation();
}
對於具體的中介者對象,主要是實現自己的業務方法,封裝同事之間的調用。其代碼示例如下:
public class ConcreteMediator extends Mediator {
@Override
public void operation() {
// 通過中介者調用同事類的方法
this.colleagues.get(0).method1();
}
}
然後,需要定義一個抽象的同事類,其維持了一個抽象中介者的引用,用於調用中介者的方法。其代碼示例如下:
public abstract class Colleague {
// 維持一個抽象中介者的引用
protected Mediator mediator;
public Colleague(Mediator mediator) {
this.mediator = mediator;
}
// 聲明自身方法,處理自己的行為
public abstract void method1();
// 定義依賴方法,與中介者通信
public void method2() {
mediator.operation();
}
}
具體的同事類也比較簡單,只需要繼承自抽象同事類,然後定義好自己的行為即可。
總結
優點
中介模式的主要優點如下:
- 中介模式將一對多的關係簡化成了一對一的關係,降低了類的複雜度,簡化了對象之間的交互
- 將各同事對象解耦,增加新的中介者和新的同事類都比較方便,更好地符合“開閉原則”
- 中介者將原本分佈於多個對象間的行為集中在一起,改變這些行為只需生成新的中介者子類即可,這使得各個同事類可被重用,無須對同事類進行擴展
缺點
中介模式的主要缺點如下:
- 具體的中介者類中包含了大量同事之間的交互邏輯,可能會導致具體中介者類非常複雜
適用場景
中介模式的適用場景如下:
- 系統中對象之間存在複雜的引用關係,系統結構混亂且難以理解
- 一個對象由於引用了許多其他對象並且直接和這些對象通信,導致難以復用該對象
- 想通過一個中間類來封裝多個類中的行為,而又不想生成太多子類
源碼
在 JDK 中 java.util.Timer
就使用到了中介模式。如下是其源碼部分:
public class Timer {
private final TaskQueue queue = new TaskQueue();
private void sched(TimerTask task, long time, long period) {
if (time < 0)
throw new IllegalArgumentException("Illegal execution time.");
if (Math.abs(period) > (Long.MAX_VALUE >> 1))
period >>= 1;
synchronized(queue) {
if (!thread.newTasksMayBeScheduled)
throw new IllegalStateException("Timer already cancelled.");
synchronized(task.lock) {
if (task.state != TimerTask.VIRGIN)
throw new IllegalStateException(
"Task already scheduled or cancelled");
task.nextExecutionTime = time;
task.period = period;
task.state = TimerTask.SCHEDULED;
}
queue.add(task);
if (queue.getMin() == task)
queue.notify();
}
}
}