Mediator Pattern中介者模式,作为行为型设计模式的一种。其通过中介者实现了对各对象之间复杂的调用、关联关系的解耦,使之整体表现为松耦合的状态
现实世界的指引
就租房这件事来说,一般会有若干个租房者、若干个出租者。之前租房市场还不发达,每个租房者需要亲自和各个出租者进行对接、沟通。显然这种模式效率并不高。租房者和出租者需要两两之间建立连接。两个群体(租房群体、出租群体)的联系呈现出一种复杂的网状结构。后来房屋中介应运而生,租房者和出租者相互不再需要直接建立连接、沟通,而是都只和房屋中介进行沟通。这样就大大减轻了租房者、出租者各自的沟通成本。从而形成了以房屋中介为中心的星型结构
模式思想
在上面租房的例子中,我们通过引入房屋中介实现了将原有复杂的网状结构转换为以中介为中心的星型结构。这一宝贵的历史经验对于我们软件工程领域同样具有重大的历史意义。当系统中存在多个对象之间存在复杂的调用、关联关系、彼此之间存在复杂的网状关系时,即可以考虑通过引入中介者这一角色实现系统的松耦合。此举将一改原有对象需要持有其他各对象实例引用的复杂局面,使得各对象只需要持有中介者的引用即可,即只和中介者进行交互。而在中介者实例中,一方面其会持有所有对象实例的引用;另一方面其负责统一描述、封装各对象之间的交互关系。这一历史经验被总结为Mediator Pattern中介者模式 。在中介者模式下,其有以下几个角色
- 抽象同事角色:其是对具体同事角色的抽象定义,定义了一些通用的方法接口
- 具体同事角色:其是抽象同事角色的具体实现。其内部通过持有具体中介者角色的实例,实现与具体中介者角色的交互
- 抽象中介者角色:其定义了具体同事角色与中介者之间进行交互的方法
- 具体中介者角色:该角色则是抽象中介者角色的具体实现,其内部会持有所有具体同事角色的实例,以实现某个具体同事角色实例与其他同事角色实例的交互、联系
实现
一般项目中,我们通常会同时使用多种数据库,比如用于存储的MySQL,用于缓存服务的Redis,用于检索的ElasticSearch等等(严格来说ElasticSearch应该是一种数据检索中间件)。出于数据一致性的考虑,当某个数据库数据变动时(添加、删除数据),其他数据库需要进行同步操作,这里我们规定此三种数据库之间的数据同步规则
- 当某数据库添加数据时,其他各数据库均需添加相应数据
- 当MySQL删除数据时,Redis、ElasticSearch均需删除相应数据
- 当Redis删除数据时,ElasticSearch需删除相应数据
- 当ElasticSearch删除数据时,Redis需删除相应数据
如果不使用中介者模式,则数据同步操作就需要各数据库之间两两建立联系,相互持有引用来实现。非常不利于后期维护、拓展。而引入中介者模式就可以很好的解决这个问题,各数据库之间无需知道对方的存在,他们只负责和中介者打交道。而将数据同步操作统一在中介者中。当然中介者是需要知道各数据库的
好了,现在让我们来实现这个例子。以便大家更好的理解该模式的精髓。首先,我们定义一个抽象同事角色——即Database数据库类,其中定义各数据库通用的添加、移除、查看数据的操作
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
|
public abstract class Database {
private Mediator mediator;
public Database(Mediator mediator) { this.mediator = mediator; }
public Mediator getMediator() { return mediator; }
abstract public void add(String str);
abstract public void addData(String str);
abstract public void remove(String str);
abstract public void removeData(String str);
abstract public void showData(); }
|
然后来实现各个具体同事角色——即MySQL、Redis、ElasticSearch等数据库。可以看到,当某个数据库自己的数据发生变动时,会请求中介者进行同步操作(调用syncAddData、syncRemoveData方法)
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 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
|
public class MySQL extends Database {
private String name = "MySQL";
private List<String> list = new LinkedList<>();
public MySQL(Mediator mediator) { super(mediator); }
@Override public void add(String str) { addData(str); getMediator().syncAddData(str, name); }
@Override public void addData(String str) { list.add(str); }
@Override public void remove(String str) { removeData(str); getMediator().syncRemoveData(str, name); }
@Override public void removeData(String str) { list.remove(str); }
@Override public void showData() { String str = "<"+ name+ "> : " + list.toString(); System.out.println(str); } } ...
public class Redis extends Database {
private String name = "Redis";
private List<String> list = new LinkedList<>();
public Redis(Mediator mediator) { super(mediator); }
@Override public void add(String str) { addData(str); getMediator().syncAddData(str, name); }
@Override public void addData(String str) { list.add(str); }
@Override public void remove(String str) { removeData(str); getMediator().syncRemoveData(str, name); }
@Override public void removeData(String str) { list.remove(str); }
@Override public void showData() { String str = "<"+ name+ "> : " + list.toString(); System.out.println(str); } } ...
public class ElasticSearch extends Database {
private String name = "ElasticSearch";
private List<String> list = new LinkedList<>();
public ElasticSearch(Mediator mediator) { super(mediator); }
@Override public void add(String str) { addData(str); getMediator().syncAddData(str, name); }
@Override public void addData(String str) { list.add(str); }
@Override public void remove(String str) { removeData(str); getMediator().syncRemoveData(str, name); }
@Override public void removeData(String str) { list.remove(str); }
@Override public void showData() { String str = "<"+ name+ "> : " + list.toString(); System.out.println(str); } }
|
现在,就轮到我们的中介者角色登场了。首先定义一个抽象中介者角色——Mediator类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
public abstract class Mediator {
abstract void syncAddData(String str, String name);
abstract void syncRemoveData(String str, String name); }
|
然后实现一个用于数据同步的具体中介者,即DataSyncMediator类。可以看到,其内部持有各数据库的实例引用,并在syncAddData、syncRemoveData方法中统一实现具体的数据同步规则
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
|
public class DataSyncMediator extends Mediator { private MySQL mySQL; private Redis redis; private ElasticSearch elasticSearch;
public void setMySQL(MySQL mySQL) { this.mySQL = mySQL; }
public void setReis(Redis redis) { this.redis = redis; }
public void setElasticSearch(ElasticSearch elasticSearch) { this.elasticSearch = elasticSearch; }
@Override void syncAddData(String str, String name) { switch (name) { case "MySQL": redis.addData(str); elasticSearch.addData(str); break; case "Redis": mySQL.addData(str); elasticSearch.addData(str); break; case "ElasticSearch": mySQL.addData(str); redis.addData(str); break; } }
@Override void syncRemoveData(String str, String name) { switch (name) { case "MySQL": redis.removeData(str); elasticSearch.removeData(str); break; case "Redis": elasticSearch.removeData(str); break; case "ElasticSearch": redis.removeData(str); break; } } }
|
好了,现在让我们来实际测试下这个Demo
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
|
public class MediatorPatternDemo { public static void main(String[] args) { DataSyncMediator dataSyncMediator = new DataSyncMediator();
MySQL mySQL = new MySQL(dataSyncMediator); Redis redis = new Redis(dataSyncMediator); ElasticSearch elasticSearch = new ElasticSearch(dataSyncMediator);
dataSyncMediator.setMySQL( mySQL ); dataSyncMediator.setReis( redis ); dataSyncMediator.setElasticSearch( elasticSearch );
System.out.println("--------------- Test 1: MySQL添加数据: Aaron ---------------"); mySQL.add("Aaron"); mySQL.showData(); redis.showData(); elasticSearch.showData();
System.out.println("\n--------------- Test 2: Redis添加数据: Tony ---------------"); redis.add("Tony"); mySQL.showData(); redis.showData(); elasticSearch.showData();
System.out.println("\n--------------- Test 3: ElasticSearch添加数据: Bob,Amy,David ---------------"); elasticSearch.add("Bob"); elasticSearch.add("Amy"); elasticSearch.add("David"); mySQL.showData(); redis.showData(); elasticSearch.showData();
System.out.println("\n--------------- Test 4: MySQL移除数据: Amy ---------------"); mySQL.remove("Amy"); mySQL.showData(); redis.showData(); elasticSearch.showData();
System.out.println("\n--------------- Test 5: Redis移除数据: Aaron ---------------"); redis.remove("Aaron"); mySQL.showData(); redis.showData(); elasticSearch.showData();
System.out.println("\n--------------- Test 6: ElasticSearch移除数据: Tony ---------------"); elasticSearch.remove("Tony"); mySQL.showData(); redis.showData(); elasticSearch.showData(); } }
|
测试结果如下,符合预期。当然对于中介者模式而言,其缺点也是显然易见的。由于中介者负责实现、维护各对象实例之间的交互规则,所以会导致中介者类代码急剧膨胀复杂
参考文献
- Head First 设计模式 弗里曼著