目录
中介者模式【Mediator Pattern】,什么是中介者模式?作用?主要对象?优缺点?应用场景?实现案例?
什么是中介者模式?
中介者模式(Mediator Pattern)是一种行为型设计模式,其目的是通过引入一个中介者对象来封装对象之间的交互和通信,使得各个对象不再直接相互依赖,避免系统中的类彼此过度耦合。中介者对象在这里扮演了“中间人”的角色,负责调度和协调其他对象的行为。
中介者模式的作用?
(1)减少对象之间的耦合
在中介者模式下,各个对象通过中介者进行通信,而不需要直接引用彼此,从而降低对象间的依赖性。
(2)优化对象通信逻辑
通过将复杂的对象交互逻辑集中到中介者中,便于维护和扩展。
(3)提高系统的可扩展性和可维护性
各个对象只需要关注自身的功能逻辑,不需要关心与其他对象的交互实现。
中介者模式的主要对象
(1)中介者(Mediator)
定义对象间交互的接口;其中包含了各个同事类。
(2)具体中介者(Concrete Mediator)
负责实际的对象间通信与协调。
(3)抽象同事类(Colleague)
需要与其他对象交互的对象,但它们通过中介者进行通信。其中包含了中介者。。
(4)具体同事类(Concrete Colleague)
同事类的具体实现,承担各自的功能,并依赖中介者进行间接的通信。
中介者模式的优缺点
优点
(1)降低耦合度
对象之间不再直接相互依赖,只需与中介者打交道,减少了复杂的对象关系。
(2)集中控制交互
将交互行为集中到一个地方,有利于简化类的设计和逻辑实现。
(3)更好的扩展性
由于中介者模式隔离了对象的直接交互,因此添加或修改参与者的交互变得更加简单。
缺点
(1)中介者的复杂性增加
随着系统变大,中介者对象的逻辑可能会变得非常复杂,承担了过多的责任,导致难以维护。
(2)可能导致性能问题
如果中介者处理了过多的交互,可能引发性能瓶颈,特别是在涉及大量通信的场景中。
中介者模式应用场景
(1)GUI开发
在图形界面应用中,各个组件(如按钮、文本框等)之间可能需要进行频繁交互,而中介者可以简化这些交互的逻辑。
(2)网络协议栈
在协议栈的实现中,不同层之间的通信可以通过中介者进行协调。
(3)消息中间件
在系统设计中,中介者模式可以用于消息中间件,处理不同系统之间的消息传递和通信。
中介者模式实现案例
公司,给员工发薪水的地方,那公司就要想尽办法盈利赚钱,盈利方法则不尽相同,但是作为公司都有相同三个环节:采购、销售和库存,这个怎么说呢?
比如:一个软件公司,要开发软件,需要开发环境吧, Windows 操作系统,数据库产品等,这你得买吧,那就是采购,开发完毕一个产品还要把产品推销出去,推销出去了大家才有钱赚,不推销出
去大家都去喝西北风呀,既然有产品就必然有库存,软件产品也有库存,你总要拷贝吧,虽然是不需要占用库房空间,那也是要占用光盘或硬盘,这也是库存。
比如:做咨询服务的公司,它要采购什么?
采购知识,采购经验,这是这类企业的生存之本,销售的也是知识和经验,库存同样是知识和经验。尽然进销存是这么的重要,我们今天就来讲讲它的原理和设计,我相信很多人都已经开发过这种类型的软件,基本上都形成了固定套路,不管是单机版还是网络版,一般的做法都是通过数据库来完成相关产品的管理,相对来说还是比较简单的项目。
三个模块之间的示意图如下:
从上的示意图上可以看出:三个模块是相互依赖的,基本上是你中有我,我中有你,为什么呢?
就以一个终端销售商(什么是终端销售商?就是以服务最终客户为目标的企业,比如 XX 超市,国美电器等等)为例子,比如采购部门要采购 IBM 型号的电脑了,它是根据什么来决定采购的呢?根据两个要素:
销售情况。销售部门要反馈销售情况,畅销就多采购,滞销就不采购;
库存情况。即使是畅销产品,库存都有 1000 台了,每天才卖出去 10 台,还要采购吗?!
销售模块是企业的盈利核心,也是对其他两个模块有影响的:
库存情况。库房有货,才能销售,没货空手套白狼是不行的;
督促采购。在特殊情况下,比如一个企业客户一下子要卖 100 台电脑,你库存里自由 80 台,怎么办?
催采购部门赶快采购呀! 同样的,库存管理也对其他两个模块有影响,库房是有容积限制的,不可能无限大,所以就有了清仓处理,那就要求采购部门别采购了,同时销售部门赶快打折销售。
上面是三个模块的情况,比较简单的一个小项目,如果有十个八个这样的模块是不是就要歇菜了,我们把进销存扩充一下,如下图的情况:
是不是看到一个蜘蛛网的结构,这个别说是编写程序了,就是给人看估计能让一大批的人昏倒!每个
对象都要和其他的几个对象交流,对象越多,每个对象要交流的成本也就越多了,就单独维护这些对象的交流基本上就能让一大批程序员望而却步,这明摆着不是人干的活嘛!从这方面来,我们已经发现设计的缺陷,作为一个架构师,发现缺陷就要想办法来修改,我们思考一下,怎么来修改。
再上学的时候学习计算机讲过一些网络的基本知识,还记得网络拓扑有几种类型吗?
总线型,环型,星型,我们来想想星型拓扑是什么什么样子的,如下图:
星型网络拓扑中每个计算机通过交换机和其他计算机进行数据交换,各个计算机之间并没有直接出现
交互的情况,结构简单,而且稳定,只要中间那个交换机不瘫痪,整个网络就不会发生大的故障,公司和网吧一般都采用星型网络,那也说明星型拓扑是深得民心,那我们来想想是不是可以把这种星型结构引入到我们的设计中呢?
示意图:
加入了一个中介者作为三个模块的交流核心,每个模块之间不再相互交流,要交流就通过中介者进行, 每个模块只负责自己的业务逻辑,不属于自己的则丢给中介者来处理。
类图:
建立了两个抽象类 AbstractMediator 和 AbstractColeague,每个对象只是与中介者 Mediator 之间产
生依赖,与其他对象之间没有直接的关系,AbstractMediator 的作用是把中介者的抽象定义,定义了一个抽象方法 execute。
从类图中看,中介者模式有以下几部分组成:
(1)抽象中介者(Mediator)角色
抽象中介者角色定义统一的接口用于各同事角色之间的通信。
(2)具体中介者(Concrete Mediator)角色
具体中介者角色通过协调各同事角色实现协作行为,因此它必须依赖于各个同事角色。
(3)同事(Colleague)角色
每一个同事角色都知道中介者角色,而且与其他的同事角色通信的时候,一定要通过中介者角色协作。每个同事类的行为分为两种:一种是同事本身的行为,比如改变对象本身的状态,处理自己的行为等等,这种方法叫做自发行为(Self-Method),与其他的同事类或中介者没有任何的依赖;第二种是是必须依赖中介者才能完成的行为,叫做依赖方法(Dep-Method)。
1、抽象中介者(AbstractMediator)
package com.uhhe.common.design.mediator;
/**
* 抽象中介者
*
* @author nizhihao
* @version 1.0.0
* @date 2024/9/8 15:40
*/
public abstract class AbstractMediator {
protected Purchase purchase;
protected Sale sale;
protected Stock stock;
public AbstractMediator() {
purchase = new Purchase(this);
sale = new Sale(this);
stock = new Stock(this);
}
/**
* 中介者最重要的方法,叫做事件方法,处理多个对象之间的关系
*
* @param str 事件方法字符串
* @param objects 参数
*/
public abstract void execute(String str, Object... objects);
}
2、具体中介者(Mediator )
中介者 Mediator 有定义了多个 private 方法,其目标是处理各个对象之间的依赖关系,即是说把原有
一个对象要依赖多个对象的情况移到中介者的 private 方法中实现,在实际项目中,一般的做法是中介者按照职责进行划分,每个中介者处理一个或多个类似的关联请求。
package com.uhhe.common.design.mediator;
/**
* 具体中介者
*
* @author nizhihao
* @version 1.0.0
* @date 2024/9/8 15:40
*/
public class Mediator extends AbstractMediator {
@Override
public void execute(String str, Object... objects) {
if (str.equals("purchase.buy")) { //采购电脑
this.buyComputer((Integer) objects[0]);
} else if (str.equals("sale.sell")) { //销售电脑
this.sellComputer((Integer) objects[0]);
} else if (str.equals("sale.offsell")) { //折价销售
this.offSell();
} else if (str.equals("stock.clear")) { //清仓处理
this.clearStock();
}
}
/**
* 采购电脑
*
* @param number 采购数目
*/
private void buyComputer(int number) {
int saleStatus = super.sale.getSaleStatus();
if (saleStatus > 80) { //销售情况良好
System.out.println("采购IBM电脑:" + number + "台");
super.stock.increase(number);
} else { //销售情况不好
int buyNumber = number / 2; //折半采购
System.out.println("采购IBM电脑:" + buyNumber + "台");
}
}
/**
* 销售电脑
*
* @param number 销售数目
*/
private void sellComputer(int number) {
if (super.stock.getStockNumber() < number) {
//库存数量不够销售
super.purchase.buyIBMcomputer(number);
}
super.stock.decrease(number);
}
/**
* 折价销售电脑
*/
private void offSell() {
System.out.println("折价销售IBM电脑" + stock.getStockNumber() + "台");
}
/**
* 清仓处理
*/
private void clearStock() {
// 要求清仓销售
super.sale.offSale();
// 要求采购人员不要采购
super.purchase.refuseBuyIBM();
}
}
3、抽象同事类(AbstractColleague)
package com.uhhe.common.design.mediator;
/**
* 同事类
*
* @author nizhihao
* @version 1.0.0
* @date 2024/9/8 15:40
*/
public abstract class AbstractColleague {
protected AbstractMediator mediator;
public AbstractColleague(AbstractMediator mediator) {
this.mediator = mediator;
}
}
4、具体同事类(Concrete Colleague)
下面类是不是简化了很多,看着也清晰了很多,处理自己的职责,与外界有关系的事件处理则交
给了中介者来完成。
采购
package com.uhhe.common.design.mediator;
/**
* 采购
*
* @author nizhihao
* @version 1.0.0
* @date 2024/9/8 15:41
*/
public class Purchase extends AbstractColleague {
public Purchase(AbstractMediator mediator) {
super(mediator);
}
/**
* 采购IBM型号的电脑
*
* @param number 采购数量
*/
public void buyIBMcomputer(int number) {
super.mediator.execute("purchase.buy", number);
}
/**
* 不在采购IBM电脑
*/
public void refuseBuyIBM() {
System.out.println("不再采购IBM电脑");
}
}
销售
package com.uhhe.common.design.mediator;
import java.util.Random;
/**
* 销售
*
* @author nizhihao
* @version 1.0.0
* @date 2024/9/8 15:41
*/
public class Sale extends AbstractColleague {
public Sale(AbstractMediator mediator){
super(mediator);
}
/**
* 销售IBM型号的电脑
* @param number 销售数量
*/
public void sellIBMComputer(int number){
super.mediator.execute("sale.sell", number);
System.out.println("销售IBM电脑"+number+"台");
}
/**
* 反馈销售情况,0——100之间变化,0代表根本就没人卖,100代表非常畅销,出1一个卖一个
* @return 销售情况
*/
public int getSaleStatus(){
Random rand = new Random(System.currentTimeMillis());
int saleStatus = rand.nextInt(100);
System.out.println("IBM电脑的销售情况为:"+saleStatus);
return saleStatus;
}
/**
* 折价处理
*/
public void offSale(){
super.mediator.execute("sale.offsell");
}
}
库存
package com.uhhe.common.design.mediator;
/**
* 库存
*
* @author nizhihao
* @version 1.0.0
* @date 2024/9/8 15:41
*/
public class Stock extends AbstractColleague {
public Stock(AbstractMediator mediator) {
super(mediator);
}
/**
* 刚开始有100台电脑
*/
private static int COMPUTER_NUMBER = 100;
/**
* 库存增加
*
* @param number 增加数目
*/
public void increase(int number) {
COMPUTER_NUMBER = COMPUTER_NUMBER + number;
System.out.println("库存数量为:" + COMPUTER_NUMBER);
}
/**
* 库存降低
*
* @param number 降低数目
*/
public void decrease(int number) {
COMPUTER_NUMBER = COMPUTER_NUMBER - number;
System.out.println("库存数量为:" + COMPUTER_NUMBER);
}
/**
* 获得库存数量
*
* @return 库存数量
*/
public int getStockNumber() {
return COMPUTER_NUMBER;
}
/**
* 存货压力大了,就要通知采购人员不要采购,销售人员要尽快销售
*/
public void clearStock() {
System.out.println("清理存货数量为:" + COMPUTER_NUMBER);
super.mediator.execute("stock.clear");
}
}
5、使用场景(Client)
package com.uhhe.common.design.mediator;
/**
* 使用场景
*
* @author nizhihao
* @version 1.0.0
* @date 2024/9/8 15:42
*/
public class Client {
public static void main(String[] args) {
AbstractMediator mediator = new Mediator();
//采购人员采购电脑
System.out.println("------采购人员采购电脑--------");
Purchase purchase = new Purchase(mediator);
purchase.buyIBMcomputer(100);
//销售人员销售电脑
System.out.println("\n------销售人员销售电脑--------");
Sale sale = new Sale(mediator);
sale.sellIBMComputer(1);
//库房管理人员管理库存
System.out.println("\n------库房管理人员清库处理--------");
Stock stock = new Stock(mediator);
stock.clearStock();
}
}