中介者模式

中介者模式的定義

中介者模式的定義為:Define an object that encapsulates how a set of objectsinteract.Mediator promotes loose coupling by keeping objects from referring to each otherexplicitly,and it lets you vary their interaction independently.(用一個中介對象封裝一系列的對象交互,中介者使各對象不需要顯示地相互作用,從而使其耦合松散,而且可以獨(dú)立地改變它們之間的交互。)

中介者模式通用類圖

image.png

從類圖中看,中介者模式由以下幾部分組成:

  • Mediator 抽象中介者角色
    抽象中介者角色定義統(tǒng)一的接口,用于各同事角色之間的通信。
  • Concrete Mediator 具體中介者角色
    具體中介者角色通過協(xié)調(diào)各同事角色實(shí)現(xiàn)協(xié)作行為,因此它必須依賴于各個同事角色。
  • Colleague 同事角色
    每一個同事角色都知道中介者角色,而且與其他的同事角色通信的時候,一定要通過中介者角色協(xié)作。每個同事類的行為分為兩種:一種是同事本身的行為,比如改變對象本身的狀態(tài),處理自己的行為等,這種行為叫做自發(fā)行為(Self-Method),與其他的同事類或中介者沒有任何的依賴;第二種是必須依賴中介者才能完成的行為,叫做依賴方法(Dep-Method)。

演示代碼

今天我們的任務(wù)是設(shè)計進(jìn)銷存系統(tǒng),聽起來很像是數(shù)據(jù)庫設(shè)計,不過這次是設(shè)計模式??磮D:

image.png

我們從這個示意圖上可以看出,三個模塊是相互依賴的。我們就以一個終端銷售商(以服務(wù)最終客戶為目標(biāo)的企業(yè),比如某某超市、某某商店等)為例,采購部門要采購IBM的電腦,它根據(jù)以下兩個要素來決定采購數(shù)量。

  • 銷售情況
    銷售部門要反饋銷售情況,暢銷就多采購,滯銷就不采購。
  • 庫存情況
    即使是暢銷產(chǎn)品,庫存都有1000臺了,每天才賣出去10臺,也就不需要再采購了!
    銷售模塊是企業(yè)的贏利核心,對其他兩個模塊也有影響:
  • 庫存情況
    庫房有貨,才能銷售,空手套白狼是不行的。
  • 督促采購

經(jīng)過需求分析,我們的攻城獅就設(shè)計出了類圖。

image.png

開始工作吧??!

1.定義庫存,這是進(jìn)銷存的核心。

public class Stock {
    // 剛開始有100臺電腦
    private static int COMPUTER_NUMBER = 100;
    // 庫存增加
    public void increase(int number) {
        COMPUTER_NUMBER = COMPUTER_NUMBER + number;
        System.out.println("庫存數(shù)量為:" + COMPUTER_NUMBER);
    }
    // 庫存降低
    public void decrease(int number) {
        COMPUTER_NUMBER = COMPUTER_NUMBER - number;
        System.out.println("庫存數(shù)量為:" + COMPUTER_NUMBER);
    }
    // 獲得庫存數(shù)量
    public int getStockNumber() {
        return COMPUTER_NUMBER;
    }
    // 存貨壓力大了,就要通知采購人員不要采購,銷售人員要盡快銷售
    public void clearStock() {
        Purchase purchase = new Purchase();
        Sale sale = new Sale();
        System.out.println("清理存貨數(shù)量為:" + COMPUTER_NUMBER);
        // 要求折價銷售
        sale.offSale();
        // 要求采購人員不要采購
        purchase.refuseBuyIBM();
    }
}

庫房中的貨物數(shù)量肯定有增減,同時庫房還有一個容量顯示,達(dá)到一定的容量后就要求對一些商品進(jìn)行折價處理,以騰出更多的空間容納新產(chǎn)品。于是就有了clearStock方法,既然是清倉處理肯定就要折價銷售了。

2.庫存不足要及時補(bǔ)充,所以不能沒有采購人員

public 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電腦");
    }
}

Purchase定義了采購電腦的標(biāo)準(zhǔn):如果銷售情況比較好,大于80分,你讓我采購多少我就采購多少;銷售情況不好,你讓我采購100臺,我就采購50臺,對折采購。電腦采購?fù)戤?,需要放到庫房中,因此要調(diào)用庫存的方法,增加庫存電腦數(shù)量。

3.銷售才有利潤,才能給員工發(fā)工資。

public class Sale {
    // 銷售IBM型號的電腦
    public void sellIBMComputer(int number) {       // 訪問庫存
        Stock stock = new Stock();      // 訪問采購
        Purchase purchase = new Purchase();
        if (stock.getStockNumber() < number) { // 庫存數(shù)量不夠銷售
            purchase.buyIBMcomputer(number);
        }
        System.out.println("銷售IBM電腦" + number + "臺");
        stock.decrease(number);
    }
    // 反饋銷售情況,0——100之間變化,0代表根本就沒人賣,100代表非常暢銷,出1一個賣一個
    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電腦的銷售情況為:96
采購IBM電腦:100臺
庫存數(shù)量為:200

------銷售人員銷售電腦--------
銷售IBM電腦1臺
庫存數(shù)量為:199

------庫房管理人員清庫處理--------
清理存貨數(shù)量為:199
折價銷售IBM電腦199臺
不再采購IBM電腦

運(yùn)行結(jié)果也是我們期望的,三個不同類型的參與者完成了各自的活動。你有沒有發(fā)現(xiàn)這三個類是彼此關(guān)聯(lián)的?每個類都與其他兩個類產(chǎn)生了關(guān)聯(lián)關(guān)系。迪米特法則認(rèn)為“每個類只和朋友類交流”,這個朋友類并非越多越好,朋友類越多,耦合性越大,要想修改一個就得修改一片,這不是面向?qū)ο笤O(shè)計所期望的。

那么我們重新改進(jìn)一下吧!從設(shè)計圖開始改進(jìn)。

image.png

加入了一個中介者作為三個模塊的交流核心,每個模塊之間不再相互交流,要交流就通過中介者進(jìn)行。每個模塊只負(fù)責(zé)自己的業(yè)務(wù)邏輯,不屬于自己的則丟給中介者來處理,簡化了各模塊之間的耦合關(guān)系。類圖也要變。

image.png

重新開始工作吧!!!

1.抽象中介者,這是一切的核心。

public abstract class AbstractMediator {
    protected Purchase purchase;
    protected Sale sale;
    protected Stock stock;
        //構(gòu)造函數(shù)
    public AbstractMediator(){
        purchase = new Purchase(this);
        sale = new Sale(this);
        stock = new Stock(this);
    }
        //中介者最重要的方法,叫做事件方法,處理多個對象之間的關(guān)系
    public abstract void execute(String str,Object...objects);
}

再來看具體的中介者,我們可以根據(jù)業(yè)務(wù)的要求產(chǎn)生多個中介者,并劃分各中介者的職責(zé)。

2.具體中介者

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")){ //銷售電腦
            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){  //庫存數(shù)量不夠銷售
            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();
    }
}

中介者M(jìn)ediator定義了多個private方法,其目的是處理各個對象之間的依賴關(guān)系,就是說把原有一個對象要依賴多個對象的情況移到中介者的private方法中實(shí)現(xiàn)。在實(shí)際項(xiàng)目中,一般的做法是中介者按照職責(zé)進(jìn)行劃分,每個中介者處理一個或多個類似的關(guān)聯(lián)請求。由于要使用中介者,我們增加了一個抽象同事類,三個具體的實(shí)現(xiàn)類分別繼承該抽象類。

3.抽象同事類

public abstract class AbstractColleague {
    protected AbstractMediator mediator;
    public AbstractColleague(AbstractMediator _mediator){
        this.mediator = _mediator;
    }
}

4.分別實(shí)現(xiàn)3個同事類。

采購

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電腦");
    }
}

庫存

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("庫存數(shù)量為:"+COMPUTER_NUMBER);
    }
        //庫存降低
    public void decrease(int number){
        COMPUTER_NUMBER = COMPUTER_NUMBER - number;
        System.out.println("庫存數(shù)量為:"+COMPUTER_NUMBER);
    }
        //獲得庫存數(shù)量
    public int getStockNumber(){
        return COMPUTER_NUMBER;
    }
    //存貨壓力大了,就要通知采購人員不要采購,銷售人員要盡快銷售
        public void clearStock(){
        System.out.println("清理存貨數(shù)量為:"+COMPUTER_NUMBER);
        super.mediator.execute("stock.clear");
    }
}

銷售

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之間變化,0代表根本就沒人賣,100代表非常暢銷,出1一個賣一個
    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");
    }
}

好了終于結(jié)束了,老大要驗(yàn)收了。

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();
    }
 }

------采購人員采購電腦--------
IBM電腦的銷售情況為:52
采購IBM電腦:50臺

------銷售人員銷售電腦--------
銷售IBM電腦1臺
庫存數(shù)量為:99

------庫房管理人員清庫處理--------
清理存貨數(shù)量為:99
折價銷售IBM電腦99臺
不再采購IBM電腦

在場景類中增加了一個中介者,然后分別傳遞到三個同事類中,三個類都具有相同的特性:只負(fù)責(zé)處理自己的活動(行為),與自己無關(guān)的活動就丟給中介者處理,程序運(yùn)行的結(jié)果是相同的。從項(xiàng)目設(shè)計上來看,加入了中介者,設(shè)計結(jié)構(gòu)清晰了很多,而且類間的耦合性大大減少,代碼質(zhì)量也有了很大的提升。在多個對象依賴的情況下,通過加入中介者角色,取消了多個對象的關(guān)聯(lián)或依賴關(guān)系,減少了對象的耦合性。

嗯!這次就比較完美了。。我們的任務(wù)也就結(jié)束了。

中介者模式的優(yōu)點(diǎn)

中介者模式的優(yōu)點(diǎn)就是減少類間的依賴,把原有的一對多的依賴變成了一對一的依賴,同事類只依賴中介者,減少了依賴,當(dāng)然同時也降低了類間的耦合。

中介者模式的缺點(diǎn)

中介者模式的缺點(diǎn)就是中介者會膨脹得很大,而且邏輯復(fù)雜,原本N個對象直接的相互依賴關(guān)系轉(zhuǎn)換為中介者和同事類的依賴關(guān)系,同事類越多,中介者的邏輯就越復(fù)雜。

中介者模式的使用場景

中介者模式簡單,但是簡單不代表容易使用,很容易被誤用。在面向?qū)ο蟮木幊讨?,對象和對象之間必然會有依賴關(guān)系,如果某個類和其他類沒有任何相互依賴的關(guān)系,那這個類就是一個“孤島”,在項(xiàng)目中就沒有存在的必要了!就像是某個人如果永遠(yuǎn)獨(dú)立生活,與任何人都沒有關(guān)系,那這個人基本上就算是野人了——排除在人類這個定義之外。類之間的依賴關(guān)系是必然存在的,一個類依賴多個類的情況也是存在的,存在即合理,那是否可以說只要有多個依賴關(guān)系就考慮使用中介者模式呢?答案是否定的。中介者模式未必能幫你把原本凌亂的邏輯整理得清清楚楚,而且中介者模式也是有缺點(diǎn)的,這個缺點(diǎn)在使用不當(dāng)時會被放大,比如原本就簡單的幾個對象依賴關(guān)系,如果為了使用模式而加入了中介者,必然導(dǎo)致中介者的邏輯復(fù)雜化,因此中介者模式的使用需要“量力而行”!中介者模式適用于多個對象之間緊密耦合的情況,緊密耦合的標(biāo)準(zhǔn)是:在類圖中出現(xiàn)了蜘蛛網(wǎng)狀結(jié)構(gòu)。在這種情況下一定要考慮使用中介者模式,這有利于把蜘蛛網(wǎng)梳理為星型結(jié)構(gòu),使原本復(fù)雜混亂的關(guān)系變得清晰簡單。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容