##场景
一个公司的“进销存“买IBM电脑系统设计,销售部门要反馈销售情况,畅销的就多采购,滞销就不采购;销售前要确定库存有货才能销售。采购部门要根据销售情况和库存情况进行采购。库存情况要根据销售情况和采购情况维护库存量。根据库存量来决定是否要打折出售。
“进销存“三个模块都有自己的香味,并且与其他的模块之间行为产生关联,类似我们的办公室“同事“各干各的活,但是彼此之间有依赖、交叉,于是彼此之间就产生紧耦合,也就是一个团队。
设计“进销存“类图
Purchase 采购管理
如果销售量大于80则表示销售良好,让采购多少台电脑就采购多少台电脑,如果销售不好,则对半采购。
public class Purchase {
// 采购IBM电脑
public void buyIBMcomputer(int number) {
//访问库存
Stock stock = new Stock();
//访问销售
Sale sale = new Sale();
//查询销售状况
int saleStatus = sale.getSaleStatus();
//如果销售量大于80则表示销售良好,让采购多少台电脑就采购多少台电脑,如果销售不好,则对半采购。
if (saleStatus > 80) {
//销售状况良好
System.out.println("采购IBM电脑:" + number + " ");
stock.increase(number);
} else {
//销售状况不好 折半采购
int buyNumber = number/2;
System.out.println("采购IBM电脑" + buyNumber + " ");
}
}
//不再采购IBM电脑
public void refuseBuyIBM() {
System.out.println("不再采购IBM电脑");
}
}
Stock库存管理
如果库存量大了就要停止采购,通知销售人员,清库存,打折出售
public class Stock {
//刚开始有100台电脑
private static int COMPUTER_NUMBER = 100; //
//增加库存
public void increase(int number) {
COMPUTER_NUMBER = COMPUTER_NUMBER + number;
System.out.println("库存数量为:" + COMPUTER_NUMBER);
}
//库存降低
public void decrease(int number) {
COMPUTER_NUMBER = COMPUTER_NUMBER - number;
System.out.println("库存数量为:" + COMPUTER_NUMBER);
}
//查询库存数量
public int getStockNumber() {
return COMPUTER_NUMBER;
}
//如果库存量大了就要停止采购,通知销售人员,清库存,打折出售
public void clearStock() {
Purchase purchase = new Purchase();
Sale sale = new Sale();
System.out.println("清理存货数量" + COMPUTER_NUMBER);
//要求折价销售
sale.offSale();
//要求采购不要采购
purchase.refuseBuyIBM();
}
}
Sale 销售管理
public class Sale {
//销售IBM电脑
public void sellIBMComputer(int number) {
//访问库存
Stock stock = new Stock();
//访问采购
Purchase purchase = new Purchase();
if (stock.getStockNumber() < number) {
//库存数量不够销售,采购电脑
purchase.buyIBMcomputer(number);
}
System.out.println("销售IBM电脑"+ number + "台");
stock.decrease(number);
}
//反馈销售状态, 0-100 之间变化,100 畅销 0 没人买
public int getSaleStatus() {
//定义随机数作为当前的销售状态
Random rand = new Random(System.currentTimeMillis());
int saleStatus = rand.nextInt(100);
System.out.println("IBM电脑销售状况为" + saleStatus);
return saleStatus;
}
//折价处理
public void offSale() {
//库房有多少卖多少
Stock stock = new Stock();
System.out.println("折价销售IBM电脑" + stock.getStockNumber() + "台");
}
}
场景类
public class Client {
public static void main(String[] args) {
//采购人员采购电脑
System.out.println("------采购人员采购电脑--------");
Purchase purchase = new Purchase();
purchase.buyIBMcomputer(100);
//销售人员销售电脑
System.out.println("\n------销售人员销售电脑--------");
Sale sale = new Sale();
sale.sellIBMComputer(1);
//库房管理人员管理库存
System.out.println("\n------库房管理人员管理库存--------");
Stock stock = new Stock();
stock.clearStock();
}
}
输出:
------采购人员采购电脑--------
IBM电脑销售状况为9
采购IBM电脑50
------销售人员销售电脑--------
销售IBM电脑1台
库存数量为:99
------库房管理人员管理库存--------
清理存货数量99
折价销售IBM电脑99台
不再采购IBM电脑
运行结果是我们期望的,但是发现这三个类都是相互关联的,迪米特法则认为“每个类只和朋友类交流“,这个朋友类并非越多越好,朋友类越多,耦合性就越大,修改一处就要修改一片。这不是我们所期望的,而且当前只是“进销存“如果扩展了物流、供应商、资产管理以后 关系图应该是这样的。
这是一个蜘蛛网结构,别说是写程序了,光是看懂就要晕倒一大批人。怎么解决这个问题呢?
学过计算机网络的童鞋 应该知道,网络拓扑 有三种类型:总线型、环形、星型。
蜘蛛网状的关系图,最好是梳理成星型 形状,星型网络拓扑中,每个计算机只用和中间的计算机进行数据交换,各个计算机之间不出现交互情况,这种结构简单而且稳定,只要中间的计算机不出现故障整个网络都不会发生大的故障。
##应用中介者模式
根据上面说的需求将 蜘蛛网 关系转化为 星状 关系刚好是 中介者模式 (调停者模式)的能力啊。关系图梳理如下:
每个模块之间不再相互交流,交流都通过中介者进行。每个模块都只负责自己的业务,其他的都丢给中介者处理,降低了模块间的耦合关系。类图如下:
新增两个抽象类AbstractMediator和AbstractColeague ,AbstractMediator是 具体中介者的抽象定义,AbstractColeague是同事类(同事类:指的就是 “进销存模块“)的抽象定义。
//定义抽象的好处就是又可以 定义方法也可以定义接口。
public abstract class AbstractMediator {
protected Purchase purchase;
protected Sale sale;
protected Stock stock;
//构造函数,创建中介者的时候新建了 三个同事类
public AbstractMediator() {
purchase = new Purchase();
sale = new Sale();
stock = new Stock();
}
//中介者中最重要的方法、事件方法,处理多个对象的关系
public abstract void execute(String str,Object...objects);
}
Mediator 中介者,我们可以根据业务需要产生多个中介者,并划分职责。
/**
* Created by yangyibo on 17/8/3.
* 具体的中介者
* 将原有的一对多 的依赖转移到了中介者的private 方法中实现,同事类只依赖中介者,减少了依赖,降低了类间的耦合。
* 在实际项目中,中介者是按照职责划分的,每个中介者处理一个或多个类似的关联请求
* 具体处理关系和执行,通过中介者取消了 stock、purchase、sale 多个类之间的耦合关系
*/
public class Mediator extends AbstractMediator {
//中介者最重要的方法
public void execute(String str, Object... objects) {
if (str.equals("purchase.buy")) { //采购电脑
this.buyComputer((Integer) objects[0]);
} else if (str.equals("sale.sell")) { //销售IBM电脑
this.sellComputer((Integer) objects[0]);
} else if (str.equals("sale.offsell")) { //打折促销
this.offSale();
} else if (str.equals("stock.clear")) { //清库存
this.clearStock();
}
}
// 采购电脑
private void buyComputer(int number) {
//查询销售状况
int saleStatus = sale.getSaleStatus();
if (saleStatus > 80) {
//销售状况良好
System.out.println("采购IBM电脑:" + number + "台");
super.stock.increase(number);
} else {
//销售状况不好 折半采购
int buyNumber = number / 2;
System.out.println("采购IBM电脑" + buyNumber + "台");
}
}
//销售IBM电脑
private void sellComputer(int number) {
//访问库存
if (super.stock.getStockNumber() < number) {
//库存数量不够销售,采购电脑
super.purchase.buyIBMcomputer(number);
}
System.out.println("销售IBM电脑" + number + "台");
super.stock.decrease(number);
}
//打折促销
private void offSale() {
//库房有多少卖多少
System.out.println("折价销售IBM电脑" + stock.getStockNumber() + "台");
}
//清库存,停止采购,打折出售
private void clearStock() {
//要求折价销售
super.sale.offSale();
//要求采购不要采购
super.purchase.refuseBuyIBM();
}
}
同事类抽象
public abstract class AbstractColleague {
protected AbstractMediator mediator;
//传递进来中介者
public AbstractColleague(AbstractMediator _mediator) {
this.mediator = _mediator;
}
调整简化Purchase 并作为同事类 继承 AbstractColleague 抽象
public class Purchase extends AbstractColleague {
//继承 抽象获取构造函数
public Purchase(AbstractMediator _mediator) {
super(_mediator);
}
// 修改 调用抽象中的 中介者,让其执行 方法
//采购IBM
public void buyIBMcomputer(int number) {
super.mediator.execute("purchase.buy", number);
}
//不再采购IBM
public void refuseBuyIBM() {
System.out.println("不再采购IBM");
}
}
调整简化Sale 并作为同事类 继承 AbstractColleague 抽象
public class Sale extends AbstractColleague {
public Sale(AbstractMediator _mediator) {
super(_mediator);
}
//销售IBM电脑
public void sellIBMComputer(int number) {
super.mediator.execute("sale.sell", number);
System.out.println("销售IBM电脑"+ number + "台");
}
//反馈销售状态, 0-100 之间变化,100 畅销 0 没人买
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");
}
}
调整简化Stock 并作为同事类 继承 AbstractColleague 抽象
public class Stock extends AbstractColleague {
public Stock(AbstractMediator _mediator) {
super(_mediator);
}
//刚开始有100台电脑
private static int COMPUTER_NUMBER = 100;
//增加库存
public void increase(int number) {
COMPUTER_NUMBER = COMPUTER_NUMBER + number;
System.out.println("库存数量为:" + COMPUTER_NUMBER);
}
//库存降低
public void decrease(int number) {
COMPUTER_NUMBER = COMPUTER_NUMBER - number;
System.out.println("库存数量为:" + COMPUTER_NUMBER);
}
//查询库存数量
public int getStockNumber() {
return COMPUTER_NUMBER;
}
//修改
//清库存,停止采购,打折出售
public void clearStock() {
System.out.println("清理存货数量" + COMPUTER_NUMBER);
super.mediator.execute("stock.clear");
}
}
调整 Client
/**
* Created by yangyibo on 17/8/3.
* 创建一个中介者,然后分别传递到三个同事类,三个同事类都只负责自己的活动,与自己无关的活动就丢给中介者。
*/
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("------销售人员销售电脑--------");
Sale sale = new Sale(mediator);
//卖了1台
sale.sellIBMComputer(1);
//库房管理人员管理库房
System.out.println("------库房管理人员管理库房------");
Stock stock = new Stock(mediator);
stock.clearStock();
}
}
结果:
略
通过使用 中介者角色,设计结构清晰了许多,取消了多个对象的关联或依赖关系,减少了对象的耦合性。
##定义
用一个中介对象封装一系列的对象交互,中介者使各对象不需要显示地相互作用,从而使其耦合松散,而且可以独立的改变他们之间的交互。
##通用类图
##组成部分
-
Mediator 抽象中介者角色,抽象中介者角色定义统一的接口,用于各个角色之间的通信。
-
Concrete Mediator 具体中介者角色,通过协调各同事角色实现协作行为,因此它必须依赖于各个同事角色。
-
Colleague 同事角色抽象,每个同事角色都继承此抽象 都知道中介者角色,与其他的同事角色通信时,通过中介者角色协作。
每个同事类的行为分为两种:一种是同事本身的行为,处理自己的行为等,这种行为叫做自发行为(Self-Method),与其他的同事类没有任何的依赖;第二种是必须依赖中介者才能完成的行为,叫做依赖方法(Dep-Method)。
##中介者模式的优点:
中介者模式的优点就是减少类间的依赖,把原有的一对多的依赖变成了一对一的依赖,同事类只依赖中介者,减少了依赖,当然同时也降低了类间的耦合。
##中介者模式的缺点
中介者模式的缺点就是中介者会膨胀的很大,而且逻辑很复杂,原本N个 对象直接的相互依赖关系转为 中介者和同事类的依赖关系,同事类越多,中介者的逻辑就越复杂。
##中介者模式的使用场景
中介者模式适合用于多个对象之间紧密耦合的情况,紧密耦合的标准是;在类图中出现了蜘蛛网状的结构。在这种情况下一定要考虑使用中介者模式,这有利于把蜘蛛网梳理为星型结构,使原本复杂混乱的关系变得清晰简单。
当出现如下情况尝试使用中介者模式:
- N个对象之间产生了相互的依赖关系(N>2)
- 多个对象有依赖关系,但是依赖香味尚不确定或者有发生改变的可能,这种情况下一般建议采用中介者模式,降低变更引起的风险扩散。
##中介者模式的实际应用
中介者模式也叫做调停者模式,一个对象要额N多个对象交流,就像对象之间的战争,很混乱,这个时需要加入一个中心,所有的类都和中心交流。中心说怎么处理就怎么处理。比如说生活中常见的例子:
###机场调度中心
机场调度中心 就是具体的中介者,用来调度每一架飞机的降落和起飞。比如某架飞机到机场上空了,就询问调度中心,是否可以降落,应当降落在哪个跑道,停在哪个停机坪 等情况,如果没有机场调度中心 那么飞行员 就要自己去看看有没有飞机和自己一起降落,有没有空的跑道,是否具备停机坪等情况。
###MVC框架
###中介服务
本文摘引自《设计模式之禅(第2版)》
本文源码:https://github.com/527515025/Design_pattern/tree/master/intermediary