1:中介者模式
中介者模式是一种行为设计模式,能让你减少对象之间混乱无序的依赖关系。该模式会限制对象之间的直接交互,迫使它们通过一个中介者对象进行合作。
2:中介者模式问题
在现实生活中,常常会出现好多对象之间存在复杂的交互关系,这种交互关系常常是“网状结构”,它要求每个对象都必须知道它需要交互的对象。例如,每个人必须记住他(她)所有朋友的电话;而且,朋友中如果有人的电话修改了,他(她)必须让其他所有的朋友一起修改,这叫作“牵一发而动全身”,非常复杂。
3:中介者模式解决方案
中介者模式建议你停止组件之间的直接交流并使其相互独立。这些组件必须调用特殊的中介者对象,通过中介者对象重定向调用行为,以间接的方式进行合作。最终,组件仅依赖于一个中介者类,无需与多个其他组件相耦合。
如果把这种“网状结构”改为“星形结构”的话,将大大降低它们之间的“耦合性”,这时只要找一个“中介者”就可以了。如前面所说的“每个人必须记住所有朋友电话”的问题,只要在网上建立一个每个朋友都可以访问的“通信录”就解决了。这样的例子还有很多,例如,你刚刚参加工作想租房,可以找“房屋中介”;或者,飞机的起飞与降落不是通过互相沟通,而是通过塔台来确定。
4:中介者模式结构
- 组件(Component)是各种包含业务逻辑的类。每个组件都有一个指向中介者的引用,该引用被声明为中介者接口类型。组件不知道中介者实际所属的类,因此你可通过将其连接到不同的中介者以使其能在其他程序中复用。
- 中介者(Mediator)接口声明了与组件交流的方法,但通常仅包括一个通知方法。组件可将任意上下文(包括自己的对象)作为该方法的参数 只有这样接收组件和发送者类之间才不会耦合。
- 具体中介者(Concrete Mediator)封装了多种组件间的关系。具体中介者通常会保存所有组件的引用并对其进行管理,甚至有时会对其生命周期进行管理。
- 组件并不知道其他组件的情况。如果组件内发生了重要事件,它只能通知中介者。中介者收到通知后能轻易地确定发送者,这或许已足以判断接下来需要触发的组件了。
对于组件来说,中介者看上去完全就是一个黑箱。发送者不知道最终会由谁来处理自己的请求,接收者也不知道最初是谁发出了请求。
代码示例:
模拟房屋中介
1 2 3 4 5 6 7 8 9 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 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
|
interface Madiator {
void register(Customer member);
void relay(String from, String msg); }
class HousingAgency implements Madiator { public List<Customer> customers = new ArrayList<>();
@Override public void register(Customer member) { if (!customers.contains(member)) { customers.add(member); member.setMadiator(this); } }
@Override public void relay(String from, String msg) { customers.forEach(e -> { String name = e.getName(); if (!name.equals(from)) { e.receive(from, msg); } });
} }
abstract class Customer { protected Madiator madiator; protected String name;
public Customer(String name) { this.name = name; }
public Madiator getMadiator() { return madiator; }
public void setMadiator(Madiator madiator) { this.madiator = madiator; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public abstract void send(String msg);
public abstract void receive(String from, String msg); }
class Seller extends Customer { Seller(String name) { super(name); }
@Override public void send(String msg) { System.out.println(name+"页面中:我(卖方)说:" + msg); madiator.relay(name, msg); }
@Override public void receive(String from, String msg) { System.out.println(name+"页面中:"+from + "说:" + msg); } }
class Buyer extends Customer { public Buyer(String name) { super(name); }
@Override public void send(String msg) { System.out.println(name+"页面中:"+"我(买方)说:" + msg); madiator.relay(name, msg); }
@Override public void receive(String from, String msg) { System.out.println(name+"页面中:"+from + "说:" + msg);
} }
public class Intermediary { public static void main(String[] args) { Madiator madiator = new HousingAgency(); Customer member1 = new Seller("张三"); Customer member2 = new Buyer("李四"); madiator.register(member1); madiator.register(member2);
member1.send("卖房啦卖房啦"); member2.send("几室几厅啊"); member1.send("三室一厅双卫"); member2.send("多少钱啊"); member1.send("不要钱,免费送"); member2.send("白送?我要了"); } }
|
输出如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| 张三页面中:我(卖方)说:卖房啦卖房啦 李四页面中:张三说:卖房啦卖房啦 李四页面中:我(买方)说:几室几厅啊 张三页面中:李四说:几室几厅啊 张三页面中:我(卖方)说:三室一厅双卫 李四页面中:张三说:三室一厅双卫 李四页面中:我(买方)说:多少钱啊 张三页面中:李四说:多少钱啊 张三页面中:我(卖方)说:不要钱,免费送 李四页面中:张三说:不要钱,免费送 李四页面中:我(买方)说:白送?我要了 张三页面中:李四说:白送?我要了
分开一下: 张三页面中:我(卖方)说:卖房啦卖房啦 张三页面中:李四说:几室几厅啊 张三页面中:我(卖方)说:三室一厅双卫 张三页面中:李四说:多少钱啊 张三页面中:我(卖方)说:不要钱,免费送 张三页面中:李四说:白送?我要了
李四页面中:张三说:卖房啦卖房啦 李四页面中:我(买方)说:几室几厅啊 李四页面中:张三说:三室一厅双卫 李四页面中:我(买方)说:多少钱啊 李四页面中:张三说:不要钱,免费送 李四页面中:我(买方)说:白送?我要了
|
5:中介者模式使用场景
- 当一些对象和其他对象紧密耦合以致难以对其进行修改时, 可使用中介者模式。
- 当组件因过于依赖其他组件而无法在不同应用中复用时, 可使用中介者模式。
- 如果为了能在不同情景下复用一些基本行为, 导致你需要被迫创建大量组件子类时, 可使用中介者模式。
6:中介者模式优缺点
优点 |
缺点 |
单一职责原则。 你可以将多个组件间的交流抽取到同一位置, 使其更易于理解和维护。 |
一段时间后, 中介者可能会演化成为上帝对象。 |
开闭原则。 你无需修改实际组件就能增加新的中介者。 |
|
你可以减轻应用中多个组件间的耦合情况。 |
|
你可以更方便地复用各个组件。 |
|
7:中介者模式与其他模式关系
- 责任链模式、命令模式、中介者模式和观察者模式用于处理请求发送者和接收者之间的不同连接方式:
- 责任链按照顺序将请求动态传递给一系列的潜在接收者,直至其中一名接收者对请求进行处理。
- 命令在发送者和请求者之间建立单向连接。
- 中介者清除了发送者和请求者之间的直接连接,强制它们通过一个中介对象进行间接沟通。
- 观察者允许接收者动态地订阅或取消接收请求。
- 外观模式和中介者的职责类似:它们都尝试在大量紧密耦合的类中组织起合作。
- 外观为子系统中的所有对象定义了一个简单接口,但是它不提供任何新功能。子系统本身不会意识到外观的存在。子系统中的对象可以直接进行交流。
- 中介者将系统中组件的沟通行为中心化。各组件只知道中介者对象,无法直接相互交流。
- 中介者和观察者之间的区别往往很难记住。在大部分情况下,你可以使用其中一种模式,而有时可以同时使用。让我们来看看如何做到这一点。
中介者的主要目标是消除一系列系统组件之间的相互依赖。这些组件将依赖于同一个中介者对象。观察者的目标是在对象之间建立动态的单向连接,使得部分对象可作为其他对象的附属发挥作用。
有一种流行的中介者模式实现方式依赖于观察者。中介者对象担当发布者的角色,其他组件则作为订阅者,可以订阅中介者的事件或取消订阅。当中介者以这种方式实现时,它可能看上去与观察者非常相似。
当你感到疑惑时,记住可以采用其他方式来实现中介者。例如,你可永久性地将所有组件链接到同一个中介者对象。这种实现方式和观察者并不相同,但这仍是一种中介者模式。
假设有一个程序,其所有的组件都变成了发布者,它们之间可以相互建立动态连接。这样程序中就没有中心化的中介者对象,而只有一些分布式的观察者。
8:中介者模式举例
从名字已经知道这个模式是干什么的了,不过我还是举个例子:租客和房东之间如果没有中介,将是一种复杂的网式结构,而中介就提供一种统一的管理方法。有什么事只需要告诉中介,中介会自行判断需要通知那些对象。
9:参考