中介者模式以实体超市(苏宁、国美等)正常运行的采购业务,销售业务,库存业务之间的配合为例子
先看类图:
Purchase负责采购管理,buyIBMComouter是指定了采购IBM电脑,refuseBuyIBM是不再采购IBM了,程序如下:
package com.example.xpeng.myapplication;
import android.util.Log;
/**
* Created by xpeng on 2018/6/24.
* 采购
*/
public class Purchase {
//采购IBM型号的电脑
public void buyIBMcomputer(int number){
//访问库存
Stock stock = new Stock();
//访问销售
Sale sale = new Sale();
//电脑的销售情况
int saleStatus = sale.getSaleStatus();
if (saleStatus>80){//销售情况良好
Log.e("xyz","采购IBM电脑:"+number+"台");
stock.increase(number);
}else{//销售情况不好
int buyNumber = number/2;
Log.e("xyz","采购IBM电脑:"+buyNumber+"台");
}
}
public void refuseBuyIBM(){
Log.e("xyz","不再采购IBM电脑");
}
}
Purchase定义了采购电脑的一个标准,如果销售情况比较好,大于80分,你让我采购多少我就采购多少;销售情况不好,你让我采购100台,我就采购50台,对这采购。电脑采购完毕了,肯定要放到库房中,因此要调用库存的方法,增加库存电脑数量。我们继续来看库房STock类:
package com.example.xpeng.myapplication;
import android.util.Log;
/**
* Created by xpeng on 2018/6/24.
*/
public class Stock {
//刚开始有100台电脑
private static int COMPUTER_NUMBER = 100;
//库存增加
public void increase(int number){
COMPUTER_NUMBER = COMPUTER_NUMBER+number;
Log.e("xyz","库存数量为:"+COMPUTER_NUMBER);
}
//库存降低
public void decrease(int number){
COMPUTER_NUMBER = COMPUTER_NUMBER - number;
Log.e("xyz","库存数量为:"+COMPUTER_NUMBER);
}
//获得库存数量
public int getStockNumber(){
return COMPUTER_NUMBER;
}
//存货压力大了,就要通知采购人员不要采购了,销售人员尽快销售
public void clearStock(){
Purchase purchase = new Purchase();
Sale sale = new Sale();
Log.e("xyz","清理存货数量为:"+COMPUTER_NUMBER);
//要求折价销售
sale.offSale();
//要求采购人员不要采购
purchase.refuseBuyIBM();
}
}
库房中毒额货物数量肯定有增加和减少了,同时库房还有一个容量显示,达到一定的容量后就要求对一些商品进行折价处理,腾出更多的空间容纳新产品,于是就有了clearStock方法,既然是清仓处理肯定就是折价销售了,于是在Sale这个类中就有了offSale方法,我们来看Sale类:
package com.example.xpeng.myapplication;
import android.util.Log;
import java.util.Random;
/**
* Created by xpeng on 2018/6/24.
*/
public class Sale {
//销售IBM型号的电脑
public void sellIBMCompyter(int number){
//访问库存
Stock stock = new Stock();
//访问采购
Purchase purchase = new Purchase();
if (stock.getStockNumber()<number){//库存数量不够销售
purchase.buyIBMcomputer(number);
}
Log.e("xyz","销售IBM电脑"+number+"台");
stock.decrease(number);
}
//反馈销售情况,0-100之间变化,0代表根本没人买,100代表非常畅销,出一个卖一个
public int getSaleStatus(){
Random random = new Random(System.currentTimeMillis());
int saleStatus = random.nextInt(100);
Log.e("xyz","IBM电脑的销售情况为:"+saleStatus);
return saleStatus;
}
//折价处理
public void offSale(){
//库房有多少卖多少
Stock stock = new Stock();
Log.e("xyz","折价销售IBM电脑:"+stock.getStockNumber()+"台");
}
}
Sale类中的getSaleStatus是获得销售情况,这个当然要出现在Sale类中,记住恰当的类放在恰当的类中,销售情况当然只有销售人员才能反馈出来了,通过百分制的机制衡量销售情况。为破门再来看场景类是怎么运行的:
private void Client() {
//采购人员采购电脑
Log.e("xyz","----采购人员采购电脑----");
Purchase purchase = new Purchase();
purchase.buyIBMcomputer(100);
//销售人员销售电脑
Log.e("xyz","\n----销售人员销售电脑---");
Sale sale = new Sale();
sale.sellIBMCompyter(1);
//库房管理人员管理库存
Log.e("xyz","\n----库存人员清理处理---");
Stock stock = new Stock();
stock.clearStock();
}
我们在场景类中模拟了三种人员类型的活动:采购人员采购电脑,销售人员销售电脑。库管员管理库存,运行结果如下:
运行结果也是我们期望的,三个不同类型的参与者完成了各自的活动。但是…,你难道就没有发现这三个类间是彼此关联的吗?每个类都与其他两个类产生了关联关系,耦合都太高,维护成本太大。
加入了一个中介者作为三个模块的交流核心,每个模块之间不再相互交流,要交流就通过中介者进行,每个模块只负责自己的业务逻辑,不属于自己的则丢给中介者来处理,看类图:
建立了两个抽象类AbstractMeduator和AbstractColeague,每个对象只是与中介者Mediator之间产生依赖,与其他对象之间没有直接的关系,AbstractMediator的作用是把中介者的抽象定义,定义了一个抽象方法execute,我们来看源码:
package com.example.xpeng.myapplication;
/**
* Created by xpeng on 2018/6/24.
*/
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源码:
package com.example.xpeng.myapplication;
import android.util.Log;
/**
* Created by xpeng on 2018/6/24.
*/
public class Mediator extends AbstractMediator {
//中介者最重要的方法
@Override
public void execute(String str, Object... objects) {
if (str.equalsIgnoreCase("purchase.buy")){//采购电脑
this.buyComputer((Integer) objects[0]);
}else if (str.equalsIgnoreCase("sale.sell")){//销售电脑
this.sellComputer((Integer) objects[0]);
}else if (str.equalsIgnoreCase("sale.offsell")){//折价销售
this.offSell();
}else if (str.equalsIgnoreCase("stock.clear")){//清仓处理
this.clearStock();
}
}
//采购电脑
private void buyComputer(int number){
int saleStatus = super.sale.getSaleStatus();
if (saleStatus>80){//销售情况良好
Log.e("xyz","采购IBM电脑:"+number+"台");
super.stock.increase(number);
}else {//销售情况不好
int buyNumber = number/2;
Log.e("xyz","采购IBM电脑:"+buyNumber+"台");
}
}
//销售电脑
private void sellComputer(int number){
if (super.stock.getStockNumber()<number){//库存数量不够销售
super.purchase.buyIBMcomputer(number);
}
super.stock.decrease(number);
}
//折价销售电脑
private void offSell(){
Log.e("xyz","折价销售IBM电脑"+stock.getStockNumber()+"台");
}
//清仓处理
private void clearStock(){
//要求清仓销售
super.sale.offSale();
//要求采购人员不要采购
super.purchase.refuseBuyIBM();
}
}
中介者Mediator有定义了多个Private方法,其目标是处理各个对象之间的依赖关系,即是说把原有一个对象要依赖多个对象的情况转移到中介者的Private方法中实现,在实际项目中,一般的做法是中介者按照职责进行划分,每个中介者处理一个或多个类似的关联请求
我们再来看AbstractCollegue源码:
package com.example.xpeng.myapplication;
/**
* Created by xpeng on 2018/6/24.
*/
public abstract class AbstractColleague {
protected AbstractMediator mediator;
public AbstractColleague(AbstractMediator _mediator){
this.mediator =_mediator;
}
}
采购类修改如下:
package com.example.xpeng.myapplication;
import android.util.Log;
/**
* Created by xpeng on 2018/6/24.
* 采购类
*/
public class PurchaseChange extends AbstractColleague{
public PurchaseChange(AbstractMediator _mediator) {
super(_mediator);
}
//采购IBM型号的电脑
public void buyIBMcomputer(int number){
super.mediator.execute("purchase.buy",number);
}
public void refuseBuyIBM(){
Log.e("xyz","不再采购IBM电脑");
}
}
再来看StockChange类:
package com.example.xpeng.myapplication;
import android.util.Log;
/**
* Created by xpeng on 2018/6/24.
* 库存类
*/
public class StockChange extends AbstractColleague{
//刚开始有100台电脑
private static int COMPUTER_NUMBER = 100;
public StockChange(AbstractMediator _mediator) {
super(_mediator);
}
//库存增加
public void increase(int number){
COMPUTER_NUMBER = COMPUTER_NUMBER+number;
Log.e("xyz","库存数量为:"+COMPUTER_NUMBER);
}
//库存降低
public void decrease(int number){
COMPUTER_NUMBER = COMPUTER_NUMBER - number;
Log.e("xyz","库存数量为:"+COMPUTER_NUMBER);
}
//获得库存数量
public int getStockNumber(){
return COMPUTER_NUMBER;
}
//存货压力大了,就要通知采购人员不要采购了,销售人员尽快销售
public void clearStock(){
// Purchase purchase = new Purchase();
// Sale sale = new Sale();
Log.e("xyz","清理存货数量为:"+COMPUTER_NUMBER);
// //要求折价销售
// sale.offSale();
// //要求采购人员不要采购
// purchase.refuseBuyIBM();
super.mediator.execute("stock.clear");
}
}
再看看销售类:
package com.example.xpeng.myapplication;
import android.util.Log;
import java.util.Random;
/**
* Created by xpeng on 2018/6/24.
*/
public class SaleChange extends AbstractColleague{
public SaleChange(AbstractMediator _mediator) {
super(_mediator);
}
//销售IBM型号的电脑
public void sellIBMCompyter(int number){
super.mediator.execute("sale.sell",number);
Log.e("xyz","销售IBM电脑"+number+"台");
}
//反馈销售情况,0-100之间变化,0代表根本没人买,100代表非常畅销,出一个卖一个
public int getSaleStatus(){
Random random = new Random(System.currentTimeMillis());
int saleStatus = random.nextInt(100);
Log.e("xyz","IBM电脑的销售情况为:"+saleStatus);
return saleStatus;
}
//折价处理
public void offSale(){
//库房有多少卖多少
super.mediator.execute("sale.offsell");
}
}
再来看场景类的变化:
private void ClientChange() {
AbstractMediator mediator = new Mediator();
//采购人员采购电脑
Log.e("xyz","----采购人员采购电脑----");
PurchaseChange purchase = new PurchaseChange(mediator);
purchase.buyIBMcomputer(100);
//销售人员销售电脑
Log.e("xyz","\n----销售人员销售电脑---");
SaleChange sale = new SaleChange(mediator);
sale.sellIBMCompyter(1);
//库房管理人员管理库存
Log.e("xyz","\n----库存人员清理处理---");
StockChange stock = new StockChange(mediator);
stock.clearStock();
}
在场景类中增加了一个中介者,然后分别传递到三个同事类中,三个类都具有相同的特性:只负责处理自己的活动,与自己无关的活动就丢给中介者处理,程序运行的结果是相同的。从项目设计上来说,加入中介者,设计结构清晰了很多,而且类间的耦合性大大减少了,代码质量也有了很大的提升。
以上讲解的模式就是中介者模式,在多个对象依赖的情况下,通过加入中介者角色,取消了多个对象的关联或依赖关系,减少了对象的耦合性,其通用类图为:
从类图中看,中介者模式有几下部分组成:
抽象中介者(Mediator)角色:抽象中介者角色定义统一的接口用于各个同时角色之间的通信。
具体中介者(Concreate Mediator)角色:具体中介者角色通过协调各同事角色实现协作行为,因此它必须依赖于各个同时角色。
同事(Colleague)角色:每一个同事角色都知道中介者角色,而且与其他的同事角色通信的时候,一定要通过中介者角色协作。每个同事类的行为分两种:一种是同事本身的行为,比如改变对象本身的状态,处理自己的行为等等,这种方法叫做自发行为(Self-Method),与其他的同事类或中介者没有任何的依赖;第二种是必须依赖中介者才能完成的行为,叫做依赖方法(Dep-Method)。
为什么同事类要使用构造函数注入而中介者使用getter/setter方式注入同事类呢?想过没有?那是因为同事类必须有中介者,而中介者可以只有部分同事类。
中介者模式的优点就是减少类间的依赖,把原有的一对多的依赖变成了一对一的依赖,同事类只依赖中介者,减少了依赖,当然也减少了类间的耦合。它的缺点呢就是中介者会膨胀的很大,而且逻辑会很负责,因为所有的原本N个对象直接的相互依赖关系转换为中介者和同事类的依赖关系,同事类越多,中介者的逻辑就复杂。
大家可以在如下的情况下尝试使用中介者模式:
1、N个对象之间产生了相互的依赖关系,其中N大于2,注意是相互的依赖;
2、多个对象有依赖关系,但是依赖的行为尚不确定或者有发生改变的可能,在这种情况下一般建议采用中介者模式,降低变更引起的风险扩散
3.产品开发。其中一个明显的例子就是MVC框架,把这个应用到产品中,可以提升产品的性能和扩展性。