工厂方法通过定义中间层,只能将两个模块解耦,当一个业务需要至少三个相互依赖的模块互相调用才能运转时,就需要在这些模块之间定义中间人模块,这种设计就是中间人模式,也叫做中介者模式。
以进销存这样的常见业务为例:
这样的业务模式就形成了相互依赖,如图:
Learn More →
在实现业务代码时,几个类之间也是牵一发而动全身:
@Deprecated
class Purchase {
// 采购IBM电脑
public void buyIBMcomputer(int number) {
// 访问库存
Stock stock = new Stock();
// 访问销售
Sale sale = new Sale();
// 电脑的销售情况
int saleStatus = sale.getSaleStatus();
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电脑");
}
}
@Deprecated
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();
}
}
@Deprecated
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之间变化,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() {
// 库房有多少卖多少
Stock stock = new Stock();
System.out.println("折价销售 IBM 电脑" + stock.getStockNumber() + "台");
}
}
public class App {
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();
}
}
中间人模式则是引入一个中间人模块作为其余模块的交流中心,每个模块只负责自己的业务逻辑,模块之间不再相互交流,要交流就通过中间人进行,从而简化了各模块之间的耦合关系:
Learn More →
使用中间人模式解耦后的类图如下:
Learn More →
在接口层面存在两个层级:AbstractMediator 和 AbstractColleague:
abstract class AbstractMediator {
protected PurchaseImpl purchase;
protected SaleImpl sale;
protected StockImpl stock;
public void setPurchase(PurchaseImpl purchase) {
this.purchase = purchase;
}
public void setSale(SaleImpl sale) {
this.sale = sale;
}
public void setStock(StockImpl stock) {
this.stock = stock;
}
public PurchaseImpl getPurchase() {
return purchase;
}
public SaleImpl getSale() {
return sale;
}
public StockImpl getStock() {
return stock;
}
// 中介者最重要的方法叫做事件方法,处理多个对象之间的关系
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 PurchaseImpl extends AbstractColleague {
public PurchaseImpl(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 StockImpl extends AbstractColleague {
public StockImpl(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 SaleImpl extends AbstractColleague {
public SaleImpl(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 Client {
public static void main(String[] args) {
AbstractMediator mediator = new Mediator();
PurchaseImpl purchaseImpl = new PurchaseImpl(mediator);
SaleImpl saleImpl = new SaleImpl(mediator);
StockImpl stockImpl = new StockImpl(mediator);
mediator.setPurchase(purchaseImpl);
mediator.setSale(saleImpl);
mediator.setStock(stockImpl);
//采购人员采购电脑
System.out.println("------采购人员采购电脑--------");
purchaseImpl.buyIBMcomputer(100);
//销售人员销售电脑
System.out.println("\n------销售人员销售电脑--------");
saleImpl.sellIBMComputer(1);
//库房管理人员管理库存
System.out.println("\n------库房管理人员清库处理--------");
stockImpl.clearStock();
}
}
显而易见,减少类间的依赖,把原有的一对多的依赖变成了一对一的依赖,同事类只依赖中介者,减少了依赖,当然同时也降低了类间的耦合。
中间人层会因业务模块的增加变得越加复杂
中间人模式简单,但是简单不代表容易使用,很容易被误用。在面向对象的编程中,对象和对象之间必然会有依赖关系,如果某个类和其他类没有任何相互依赖的关系,那这个类就是一个“孤岛”,在项目中就没有存在的必要了!类之间的依赖关系是必然存在的,一个类依赖多个类的情况也是存在的,存在即合理,那是否可以说只要有多个依赖关系就考虑使用中间人模式呢?答案是否定的。中间人模式未必能帮你把原本凌乱的逻辑整理得清清楚楚,而且中间人模式也是有缺点的,这个缺点在使用不当时会被放大,比如原本就简单的几个对象依赖关系,如果为了使用模式而加入了中间人,必然导致中间人的逻辑复杂化,因此中间人模式的使用需要“量力而行”!中间人模式适用于多个对象之间紧密耦合的情况,紧密耦合的标准是:在类图中出现了蜘蛛网状结构。在这种情况下一定要考虑使用中间人模式,这有利于把蜘蛛网梳理为星型结构,使原本复杂混乱的关系变得清晰简单。
最后,中间人模式很少使用接口或抽象类,这与依赖倒置原则是冲突的,也是由于中间人模式的特点而决定:
中介者模式是一个非常好的封装模式,也是一个很容易被滥用的模式,一个对象依赖几个对象是再正常不过的事情,且使用中介模式就必然会带来中介者的膨胀问题,但是要求使用中介者模式来封装这种依赖关系,这在一个项目中是很不恰当的。当业务模块之间产生 N-N 依赖关系,且不确定不确定或者有发生改变的可能,在这种情况下一般建议采用中介者模式,降低变更引起的风险扩散,典型的就是产品开发,往往在迭代的过程中存在诸多不确定性,使用中间人模式能够将细分的模块组合成灵活的功能。与之相对的是项目开发,已项目验收为目标,设计相对固定,在明确了模块之间有 N-N 依赖,则使用中间人模式。
根據 WSL Config 介紹中的 Automount Settings章節描述,WSL 會默認將 windows 磁碟分區通過 DrfFS 檔案系統掛載到 /mnt 路徑下。
Aug 30, 2023linux2023: ahbji
Aug 20, 2023View the book with “<i class="fa fa-book fa-fw"></i> Book Mode”.
Aug 11, 2023View the book with “<i class="fa fa-book fa-fw"></i> Book Mode”.
Aug 9, 2023or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up