23种设计模式8_中介者模式
1 基本介绍
中介者模式:用一个中介者对象封装一系列对象的交互关系,从而使各个对象之间不需要显式的相互作用,降低他们的耦合性,而且可以独立地改变他们之间的交互。
UML类图如下:
从类图中可以看出有三种角色:
Mediator抽象中介者角色 抽象中介者角色定义统一接口,用于各同事之间的通信。
ConcreteMediator具体中介者角色 具体中介者角色通过协调各同事角色实现协作行为,因此他必须依赖各个同事角色。
Colleague同事类角色 同事类角色与其他同事类角色进行交互的时候需要通过中介者角色来协调。同事类角色根据具体的业务逻辑可以有很多个,每个分工不同,彼此之间又互相耦合产生关联。同事类角色的行为可以分为两种:一种是角色本身的行为,只改变自己本身的行为/状态,这种行为也成为自发行为(Self-Method);另一种是通过中介者与其他同事类角色产生交互的行为,因为需要依赖中介者,也被成为依赖方法(Dep-Method)。
2 案例演示
需求:进销存系统(买卖笔记本电脑)
三个角色:采购,销售,仓库。
交互:
①采购进行采购商品的时候需要问仓库还有多少库存,问销售哪些好卖哪些不好卖
②销售卖产品也需要问仓库还有多少库存,没有的需要联系采购进行购买
③仓库管理库存也是需要根据采购情况和销售情况的
2.1 常规实现
采购
public class PurchaseColleague {
// 购买
public void bugLaptop() {
StockCollegue stockCollegue = new StockCollegue();
SaleCollegue saleCollegue = new SaleCollegue();
// 1.笔记本库存不够
boolean flag1 = stockCollegue.getLaptopStockCount() < 5;
// 2.笔记本销量比较好,且仓库还有空闲,再采购一批
boolean flag2 = saleCollegue.getSaleInfo() && stockCollegue.getLaptopStockCount() < 15;
if ( flag1 || flag2 ) {
System.out.println("采购购买笔记本5台");
// 库存入库5台笔记本电脑
stockCollegue.increse(5);
}
}
// 不购买
public void refuseBugLaotop() {
StockCollegue stockCollegue = new StockCollegue();
SaleCollegue saleCollegue = new SaleCollegue();
// 1.仓库笔记本囤货足够,不需要购买了
boolean flag1 = stockCollegue.getLaptopStockCount() > 15;
// 2.销售行情不好,也不采购
boolean flag2 = saleCollegue.getSaleInfo();
if (flag1 || !flag2) {
System.out.println("暂时不需要购买笔记本电脑了");
}
}
}
销售
public class SaleCollegue {
// 返回销售行情
public boolean getSaleInfo() {
// 这里就用0,1表示销售行情
Random random = new Random(2);
if (random.nextInt() == 1) {
System.out.println("销售行情好");
return true;
} else {
System.out.println("销售行情不好");
return false;
}
}
// 卖电脑
public void saleLaptop(int num) {
PurchaseColleague purchaseColleague = new PurchaseColleague();
StockCollegue stockCollegue = new StockCollegue();
// 卖电脑先要问一下有没有库存了,如果没有了,就需要联系采购进行购买
if (stockCollegue.getLaptopStockCount() < num) {
System.out.println("库存不够,采购购买电脑");
purchaseColleague.bugLaptop();
return;
}
// 如果还有库存,假设每次卖出去一台电脑,仓库需要更新库存
System.out.println("卖出去" + num + "台电脑");
stockCollegue.decrese(num);
}
// 库存很多,打折促销
public void discount() {
StockCollegue stockCollegue = new StockCollegue();
if (stockCollegue.getLaptopStockCount() > 15) {
System.out.println("打折促销!!!卖出6台电脑");
saleLaptop(6);// 每次促销卖出去6台
}
}
}
仓库
public class StockCollegue {
// 库存总量是20,假设现在就8台
private static int LAPTOP_STOCK_COUNT = 8;
// 获取库存数量
public int getLaptopStockCount() {
return LAPTOP_STOCK_COUNT;
}
public void increse(int num) {
LAPTOP_STOCK_COUNT += num;
}
public void decrese(int num) {
LAPTOP_STOCK_COUNT -= num;
}
// 仓库管理员统计库存
public void manage() {
PurchaseColleague purchaseColleague = new PurchaseColleague();
SaleCollegue saleCollegue = new SaleCollegue();
// 1.库存少于5台了,而且销售行情挺好,联系采购进行购买
if (LAPTOP_STOCK_COUNT < 5 && saleCollegue.getSaleInfo()) {
purchaseColleague.bugLaptop();
return;
}
// 库存快满了,联系采购暂时不要购买了,联系销售打折促销
if (LAPTOP_STOCK_COUNT > 15) {
purchaseColleague.refuseBugLaotop();
saleCollegue.discount();
}
}
}
分析:从这个代码就可以看出来,三个同事类角色之间的关联性太强了,也不方便后期的维护拓展,如果进销存系统苟能再进行扩展,增加物流,供应商,资产等等,如下:
这么一个像蜘蛛网似的结构,是不是看着就头疼,更别说编写程序实现了!
这时候就可以通过中介者模式来简化结构,如下:
这时候的结构是不是就清晰了很多,与网络拓扑中的星型网络拓扑类似。这时候每个同事类角色只需要负责自己业务逻辑,与其他同事类角色的交互都交给中介者,这样就降低了每个同事类角色直接的耦合性。
2.2 中介者模式实现
抽象中介者
public abstract class AbstractMediator {
protected PurchaseColleague purchaseColleague;
protected SaleCollegue saleCollegue;
protected StockCollegue stockCollegue;
public AbstractMediator() {
purchaseColleague = new PurchaseColleague(this);
saleCollegue = new SaleCollegue(this);
stockCollegue = new StockCollegue(this);
}
// 中介者处理多个对象之间交互的方法
public abstract void exec(String str, int num);
}
具体中介者
public class Mediator extends AbstractMediator{
@Override
public void exec(String str, int num) {
if ("purchase".equals(str)) {
purchase(num);
} else if ("sale".equals(str)) {
sale(num);
} else if ("discount".equals(str)) {
discount();
} else if ("manage".equals(str)) {
manageStock();
}
}
private void purchase(int num) {
// 1.笔记本库存不够
boolean flag1 = stockCollegue.getLaptopStockCount() < 5;
// 2.笔记本销量比较好,且仓库还有空闲,再采购一批
boolean flag2 = saleCollegue.getSaleInfo() && stockCollegue.getLaptopStockCount() < 15;
if ( flag1 || flag2 ) {
System.out.println("采购购买笔记本");
// 库存入库5台笔记本电脑
stockCollegue.increse(num);
}
}
private void sale(int num) {
// 卖电脑先要问一下有没有库存了,如果没有了,就需要联系采购进行购买
int stock = stockCollegue.getLaptopStockCount();
if (stock < num) {
System.out.println("库存不够,采购购买电脑");
purchaseColleague.bugLaptop(num - stock + 3);
return;
}
// 如果还有库存,假设每次卖出去一台电脑,仓库需要更新库存
System.out.println("卖出去" + num + "台电脑");
stockCollegue.decrese(num);
}
private void discount() {
if (stockCollegue.getLaptopStockCount() > 15) {
saleCollegue.saleLaptop(6);// 每次促销卖出去6台
}
}
private void manageStock() {
// 1.库存少于5台了,而且销售行情挺好,联系采购进行购买
int stock = stockCollegue.getLaptopStockCount();
if (stock < 5 && saleCollegue.getSaleInfo()) {
purchaseColleague.bugLaptop(5);
return;
}
// 库存快满了,联系采购暂时不要购买了,联系销售打折促销
if (stock > 15) {
purchaseColleague.refuseBugLaotop();
saleCollegue.discount();
}
}
}
抽象同事类
public abstract class AbstractColleague {
protected AbstractMediator mediator;
public AbstractColleague(AbstractMediator _mediator) {
this.mediator = _mediator;
}
}
采购
public class PurchaseColleague extends AbstractColleague{
public PurchaseColleague(AbstractMediator _mediator) {
super(_mediator);
}
// 购买
public void bugLaptop(int num) {
mediator.exec("purchase", num);
}
// 不购买
public void refuseBugLaotop() {
System.out.println("暂时不购买笔记本电脑了");
}
}
销售
public class SaleCollegue extends AbstractColleague {
public SaleCollegue(AbstractMediator _mediator) {
super(_mediator);
}
// 返回销售行情
public boolean getSaleInfo() {
// 这里就用0,1表示销售行情
double saleMsg = Math.random() * 20;
if (saleMsg > 8) {
System.out.println("销售行情好");
return true;
} else {
System.out.println("销售行情不好");
return false;
}
}
// 卖电脑
public void saleLaptop(int num) {
mediator.exec("sale", num);
}
// 库存很多,打折促销
public void discount() {
mediator.exec("discount", 6);
}
}
库存
public class StockCollegue extends AbstractColleague {
public StockCollegue(AbstractMediator _mediator) {
super(_mediator);
}
// 库存总量是20,假设现在就8台
private static int LAPTOP_STOCK_COUNT = 8;
// 获取库存数量
public int getLaptopStockCount() {
return LAPTOP_STOCK_COUNT;
}
public void increse(int num) {
LAPTOP_STOCK_COUNT += num;
}
public void decrese(int num) {
LAPTOP_STOCK_COUNT -= num;
}
// 仓库管理员统计库存
public void manage() {
mediator.exec("manage", 0);
}
}
客户端演示
public class Client {
public static void main(String[] args) {
AbstractMediator mediator = new Mediator();
PurchaseColleague purchaseColleague = new PurchaseColleague(mediator);
StockCollegue stockCollegue = new StockCollegue(mediator);
SaleCollegue saleCollegue = new SaleCollegue(mediator);
saleCollegue.saleLaptop(7);
saleCollegue.saleLaptop(3);
purchaseColleague.bugLaptop(10);
stockCollegue.manage();
}
}
分析:从上面的代码可以看出来,每个角色只需要负责自己独立的业务部分,需要与其他角色交互的都委托给中介者。同事类与同事类之间没有直接关系,降低了耦合。
两个细节:
①中介者**Mediator
**类中定义同事类的注入,但是没有使用抽象同事类注入?
因为同事类虽然有抽象,但是没有每个同事类必须要完成的业务,如果有的话,就注入抽象同事类,做到依赖倒置原则。
②为什么同事类使用构造注入中介者,而中介者使用getter/setter或者new的方式关联同事类?
因为同事类交互必须通过中介者,而中介者却可以只有部分同事类。
3 中介者模式的应用
3.1 优缺点
优点
①结构清晰,不复杂
②减少类间的依赖,降低耦合
缺点
同事类越多,逻辑越复杂,中介者就会越膨胀
3.2 使用场景
类之间的依赖是必然存在的,多个类之间的互相依赖也是存在的,但是并不是所有的这些依赖情况都可以通过中介者模式来理清,如果使用不好,反而会使逻辑更加复杂。所以中介者模式多适用于紧耦合的逻辑关系中,像上面的网状结构就是属于紧耦合,这时候就可以考虑使用中介者模式。遇到以下情况时可以考虑使用中介者模式:
① N个对象之间产生了相互的依赖关系(N>2);
② 多个对象之间有依赖关系,但是依赖的具体行为尚不确定或者后期需要改变的情况,也可以考虑使用中介者模式,降低后期变更引起的风险。
tter或者new的方式关联同事类?
因为同事类交互必须通过中介者,而中介者却可以只有部分同事类。
3 中介者模式的应用
3.1 优缺点
优点
①结构清晰,不复杂
②减少类间的依赖,降低耦合
缺点
同事类越多,逻辑越复杂,中介者就会越膨胀
3.2 使用场景
类之间的依赖是必然存在的,多个类之间的互相依赖也是存在的,但是并不是所有的这些依赖情况都可以通过中介者模式来理清,如果使用不好,反而会使逻辑更加复杂。所以中介者模式多适用于紧耦合的逻辑关系中,像上面的网状结构就是属于紧耦合,这时候就可以考虑使用中介者模式。遇到以下情况时可以考虑使用中介者模式:
① N个对象之间产生了相互的依赖关系(N>2);
② 多个对象之间有依赖关系,但是依赖的具体行为尚不确定或者后期需要改变的情况,也可以考虑使用中介者模式,降低后期变更引起的风险。