一、引言:
中介者模式用于处理多个类高耦合的场景,类似于星型拓扑结构,在该结构中抽象出一个中介者,并配备同事类,实现不同的业务逻辑。
该模式有三部分组成:中介者-同事-业务实现类。
抽象中介者定义统一的接口,用于各同事角色之间通信,具体中介者用于协调各同事角色最终的协作,必须依赖各个同事,同事角色不能与其他同事类有依赖,如果需要的话,必须通过中介者才能完成。
中介者的模式好处是减少类中的依赖,降低了类间的耦合;但是缺点是同事类越多,中介者的逻辑就越复杂。
该模式适用的场景:机场调度中心、MVC框架、媒体网关、中介服务等。
二、中介者demo:
我们假定一个经销商采购、库存和销售电脑。使用中介者模式实现电脑的采购存储和售卖。紧抓上面的三部分,首先是中介者:
/** 抽象中介者 */
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);
}
/* 中介者最重要的方法叫做事件方法, 处理多个对象之间的关系 */
public abstract void execute(String str,Object...objects);
}
抽象中介者首先实例化具体的业务实现类,下面是具体中介者,执行具体的任务:
/** 具体中介者 */
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")){
this.sellComputer((Integer)objects[0]);
}else if(str.equals("sale.offsell")){
this.offSell();
}else if(str.equals("stock.clear")){
this.clearStock();
}
}
/* 采购电脑 */
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+ "台");
}
}
/* 销售电脑 */
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();
}
}
接下来是抽象同事类和具体同事类:
/** 抽象同事类 */
abstract class AbstractColleague {
protected AbstractMediator mediator;
public AbstractColleague(AbstractMediator mediator){
this.mediator = mediator;
}
}
/** 采购管理 */
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电脑");
}
}
/** 库存管理 */
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");
}
}
/** 销售管理 */
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变化, 0代表根本就没人买, 100代表非常畅销, 出一个卖一个
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");
}
}
同事类的特点是之间没有耦合,如果有依赖必须通过中介者来完成。
最后是测试代码:
public class MediatorDesign {
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();
}
}
client端代码只需要实例化中介者,然后通过中介者去实现具体的需求和业务,至于是如何实现的,这不是client端需要了解的问题。
三、命令模式:
命令模式是一种高内聚的设计模式:
命令模式使用的场景:GUI开发中的按钮点击等。
命令模式的思路:client-Invoker-command-receiver。假如对于一款软件开发,client类似现实生活中的用户,Invoker则相当于软件的产品经理,Invoker通过command去指挥下面的receiver,receiver是谁?就是软件开发的需求组,前端,后端,UI等等。对应用户而言,希望的是我对软件的看法或者意见直接给产品经理反馈,至于找谁来做,那不是用户关心的事。这个模式尽量保证client少跟receiver打交道,该模式的优点是架构清晰明了,但是有一个缺点是如果命令很多的话,那么继承command的子类也会非常多。
四、命令模式demo:
package com.example.javatestlib;
/** 抽象组 */
abstract class Group {
//甲乙双方分开办公, 如果你要和某个组讨论, 你首先要找到这个组
public abstract void find();
//被要求增加功能
public abstract void add();
//被要求删除功能
public abstract void delete();
//被要求修改功能
public abstract void change();
//被要求给出所有的变更计划
public abstract void plan();
}
/** 需求组 */
class RequirementGroup extends Group {
public void find() {
System.out.println("找到需求组...");
}
public void add() {
System.out.println("客户要求增加一项需求...");
}
public void change() {
System.out.println("客户要求修改一项需求...");
}
public void delete() {
System.out.println("客户要求删除一项需求...");
}
public void plan() {
System.out.println("客户要求需求变更计划...");
}
}
/** 美工组 */
class PageGroup extends Group {
public void find() {
System.out.println("找到美工组...");
}
public void add() {
System.out.println("客户要求增加一个页面...");
}
public void change() {
System.out.println("客户要求修改一个页面...");
}
public void delete() {
System.out.println("客户要求删除一个页面...");
}
public void plan() {
System.out.println("客户要求页面变更计划...");
}
}
/** 代码组 */
class CodeGroup extends Group {
//客户要求代码组过去和他们谈
public void find() {
System.out.println("找到代码组...");
}
public void add() {
System.out.println("客户要求增加一项功能...");
}
public void change() {
System.out.println("客户要求修改一项功能...");
}
public void delete() {
System.out.println("客户要求删除一项功能...");
}
public void plan() {
System.out.println("客户要求代码变更计划...");
}
}
/** 命令抽象类 */
abstract class Command {
/* 把三个组都定义好, 子类可以直接使用 */
protected RequirementGroup rg = new RequirementGroup(); //需求组
protected PageGroup pg = new PageGroup(); //美工组
protected CodeGroup cg = new CodeGroup(); //代码组
public abstract void execute();
}
/** 命令具体类:增加需求类 */
class AddRequirementCommand extends Command {
public void execute() {
super.rg.find();
super.rg.add();
super.rg.plan();
}
}
/** 命令具体类:删除页面类 */
class DeletePageCommand extends Command {
public void execute() {
super.pg.find();
super.rg.delete();
super.rg.plan();
}
}
/** 负责人invoker */
class Invoker {
/* 管理命令 */
private Command command;
/* 客户发出的命令 */
public void setCommand(Command command){
this.command = command;
}
/* 执行客户的命令 */
public void action(){
this.command.execute();
}
}
public class CommondDesign {
public static void main(String[] args) {
Invoker xiaoSan = new Invoker();
System.out.println("------------客户要求增加一项需求---------------");
Command command = new AddRequirementCommand();
xiaoSan.setCommand(command);
xiaoSan.action();
}
}
博客参考书籍:秦小波 《设计模式之禅(第2版)》