中介者模式

来源:https://www.cnblogs.com/wangkaihua/archive/2018/07/14/9311153.html
-Advertisement-
Play Games

中介者模式 標簽 : 設計模式 初識中介者模式 定義 用一個中介對象來封裝一系列的對象交互。中介者使得各對象不需要顯式地相互引用,從而使其耦合鬆散,而且可以獨立的改變它們之間的交互。 結構和說明 ![image_1cichf9j215a4eatf87cma7sm9.png 86.7kB][1] Me ...


中介者模式

標簽 : 設計模式


初識中介者模式

定義

用一個中介對象來封裝一系列的對象交互。中介者使得各對象不需要顯式地相互引用,從而使其耦合鬆散,而且可以獨立的改變它們之間的交互。

結構和說明

image_1cichf9j215a4eatf87cma7sm9.png-86.7kB

Mediator:中介者介面。在裡面定義各個同事之間交互需要的方法,可以是公共的通訊方法,比如changed方法,大家都用,也可以是小範圍的交互方法。
ConcreteMediator:具體中介者實現對象。它需要瞭解並維護各個同事對象,並負責具體的協調各同事對象的交互關係。
Colleague:同事類的定義,通常實現成為抽象類,主要負責約束同事對象的類型,並實現一些具體同事類之間的公共功能,比如:每個具體同事類都應該知道中介者對象,也就是具體同事類都會持有中介者對象,就可以定義到這個類裡面。
ConcreteColleague:具體的同事類,實現自己的業務,在需要與其它同事通訊的時候,就與持有的中介者通信,中介者會負責與其它的同事交互。

/**
 * 同事類的抽象父類
 */
public abstract class Colleague {
    /**
     * 持有中介者對象,每一個同事類都知道它的中介者對象
     */
    private Mediator mediator;
    /**
     * 構造方法,傳入中介者對象
     * @param mediator 中介者對象
     */
    public Colleague(Mediator mediator) {
        this.mediator = mediator;
    }
    /**
     * 獲取當前同事類對應的中介者對象
     * @return 對應的中介者對象
     */
    public Mediator getMediator() {
        return mediator;
    }
}


----------
/**
 * 具體的同事類A
 */
public class ConcreteColleagueA extends Colleague {
    public ConcreteColleagueA(Mediator mediator) {
        super(mediator);
    }
    /**
     * 示意方法,執行某些業務功能
     */
    public void someOperation() {
        //在需要跟其他同事通信的時候,通知中介者對象
        getMediator().changed(this);
    }
}


----------
/**
 * 具體的同事類B
 */
public class ConcreteColleagueB extends Colleague {
    public ConcreteColleagueB(Mediator mediator) {
        super(mediator);
    }
    /**
     * 示意方法,執行某些業務功能
     */
    public void someOperation() {
        //在需要跟其他同事通信的時候,通知中介者對象
        getMediator().changed(this);
    }
}


----------
/**
 * 中介者,定義各個同事對象通信的介面
 */
public interface Mediator {
    /**
     * 同事對象在自身改變的時候來通知中介者的方法,
     * 讓中介者去負責相應的與其他同事對象的交互
     * @param colleague 同事對象自身,好讓中介者對象通過對象實例
     *                  去獲取同事對象的狀態
     */
    public void changed(Colleague colleague);
}


----------


/**
 * 具體的中介者實現
 */
public class ConcreteMediator implements Mediator {
    
    /**
     * 持有並維護同事A
     */
    private ConcreteColleagueA colleagueA;
    /**
     * 持有並維護同事B
     */
    private ConcreteColleagueB colleagueB;
    
    /**
     * 設置中介者需要瞭解並維護的同事A對象
     * @param colleague 同事A對象
     */
    public void setConcreteColleagueA(ConcreteColleagueA colleague) {
        colleagueA = colleague;
    }
    /**
     * 設置中介者需要瞭解並維護的同事B對象
     * @param colleague 同事B對象
     */
    public void setConcreteColleagueB(ConcreteColleagueB colleague) {
        colleagueB = colleague;
    }
    
    public void changed(Colleague colleague) {
        //某個同事類發生了變化,通常需要與其他同事交戶
        //具體協調相應的同事對象來實現協作行為
    }

}

體會中介者模式

如果電腦裡面沒有了主板,那麼各個配件之間就必須自行相互交互,以互相傳送數據,理論上說,基本上各個配件相互之間都存在交互數據的可能
image_1cichpuabfrn1m461bn7lkqmpm.png-43kB
有了主板,各個配件的交互完全通過主板來完成,每個配件都只需要和主板交互,而主板知道如何和所有的配件打交道,那就簡單多了
image_1cichqj7g9tcc3h1gbn1vn21j6313.png-10.1kB

存在的問題
如果上面的情況發生在軟體開發上呢?
如果把每個電腦配件都抽象成為一個類或者是子系統,那就相當於出現了多個類之間相互交互,而且交互還很繁瑣,導致每個類都必須知道所有需要交互的類,也就是我們常說的類和類耦合了,是不是很麻煩?
這樣一來,不但開發的時候每個類會複雜,因為要兼顧其它的類,更要命的是每個類在發生改動的時候,需要通知所有相關的類一起修改,因為介面或者是功能發生了變動,使用它的地方都得變,太可怕了吧!
那該如何來簡化這種多個對象之間的交互呢?

使用電腦來看電影
為了演示,考慮一個稍微具體點的功能。在日常生活中,我們經常使用電腦來看電影,把這個過程描述出來,這裡僅僅考慮正常的情況,也就是有主板的情況,簡化後假定會有如下的交互過程:
1:首先是光碟機要讀取光碟上的數據,然後告訴主板,它的狀態改變了
2:主板去得到光碟機的數據,把這些數據交給CPU進行分析處理
3:CPU處理完後,把數據分成了視頻數據和音頻數據,通知主板,它處理完了
4:主板去得到CPU處理過後的數據,分別把數據交給顯卡和音效卡,去顯示出視頻和發出聲音

當然這是一個持續的、不斷重覆的過程,從而形成不間斷的視頻和聲音,具體的運行過程不在討論之列,假設就有如上簡單的交互關係就可以了。也就是說想看電影,把光碟放入光碟機,光碟機開始讀盤,就可以看電影了

使用模式的解決方案
image_1cicht1se18jblc71llg1fckrol1g.png-124.6kB

/**
 * 同事類的抽象父類
 */
public abstract class Colleague {
    /**
     * 持有中介者對象,每一個同事類都知道它的中介者對象
     */
    private Mediator mediator;
    /**
     * 構造方法,傳入中介者對象
     * @param mediator 中介者對象
     */
    public Colleague(Mediator mediator) {
        this.mediator = mediator;
    }
    /**
     * 獲取當前同事類對應的中介者對象
     * @return 對應的中介者對象
     */
    public Mediator getMediator() {
        return mediator;
    }
}


----------
/**
 * CPU類,一個同事類
 */
public class CPU extends Colleague{
    public CPU(Mediator mediator) {
        super(mediator);
    }
    /**
     * 分解出來的視頻數據
     */
    private String videoData = "";
    /**
     * 分解出來的聲音數據
     */
    private String soundData = "";
    /**
     * 獲取分解出來的視頻數據
     * @return 分解出來的視頻數據
     */
    public String getVideoData() {
        return videoData;
    }
    /**
     * 獲取分解出來的聲音數據
     * @return 分解出來的聲音數據
     */
    public String getSoundData() {
        return soundData;
    }
    /**
     * 處理數據,把數據分成音頻和視頻的數據
     * @param data 被處理的數據
     */
    public void executeData(String data){
        //把數據分解開,前面的是視頻數據,後面的是音頻數據
        String [] ss = data.split(",");
        this.videoData = ss[0];
        this.soundData = ss[1];
        //通知主板,CPU的工作完成
        this.getMediator().changed(this);
    }
    
}


----------
/**
 * 光碟機類,一個同事類
 */
public class CDDriver extends Colleague{
    public CDDriver(Mediator mediator) {
        super(mediator);
    }
    /**
     * 光碟機讀取出來的數據
     */
    private String data = "";
    /**
     * 獲取光碟機讀取出來的數據
     * @return 光碟機讀取出來的數據
     */
    public String getData(){
        return this.data;
    }
    /**
     * 讀取光碟
     */
    public void readCD(){
        //逗號前是視頻顯示的數據,逗號後是聲音
        this.data = "設計模式,值得好好研究";
        //通知主板,自己的狀態發生了改變
        this.getMediator().changed(this);
    }
}


----------
/**
 * 音效卡類,一個同事類
 */
public class SoundCard extends Colleague{
    public SoundCard(Mediator mediator) {
        super(mediator);
    }
    
    /**
     * 按照聲頻數據發出聲音
     * @param data 發出聲音的數據
     */
    public void soundData(String data){
        System.out.println("畫外音:"+data);
    }
    
}


----------
/**
 * 顯卡類,一個同事類
 */
public class VideoCard extends Colleague{
    public VideoCard(Mediator mediator) {
        super(mediator);
    }
    
    /**
     * 顯示視頻數據
     * @param data 被顯示的數據
     */
    public void showData(String data){
        System.out.println("您正觀看的是:"+data);
    }
    
}


----------
/**
 * 中介者對象的介面
 */
public interface Mediator {
    /**
     * 同事對象在自身改變的時候來通知中介者的方法,
     * 讓中介者去負責相應的與其他同事對象的交互
     * @param colleague 同事對象自身,好讓中介者對象通過對象實例
     *                  去獲取同事對象的狀態
     */
    public void changed(Colleague colleague);
}


----------
/**
 * 主板類,實現中介者介面
 */
public class MotherBoard implements Mediator{
    /**
     * 需要知道要交互的同事類——光碟機類
     */
    private CDDriver cdDriver = null;
    /**
     * 需要知道要交互的同事類——CPU類
     */
    private CPU cpu = null;
    /**
     * 需要知道要交互的同事類——顯卡類
     */
    private VideoCard videoCard = null;
    /**
     * 需要知道要交互的同事類——音效卡類
     */
    private SoundCard soundCard = null;

    public void setCdDriver(CDDriver cdDriver) {
        this.cdDriver = cdDriver;
    }
    public void setCpu(CPU cpu) {
        this.cpu = cpu;
    }
    public void setVideoCard(VideoCard videoCard) {
        this.videoCard = videoCard;
    }
    public void setSoundCard(SoundCard soundCard) {
        this.soundCard = soundCard;
    }
    
    public void changed(Colleague colleague) {
        if(colleague == cdDriver){
            //表示光碟機讀取數據了
            this.opeCDDriverReadData((CDDriver)colleague);
        }else if(colleague == cpu){
            //表示CPU處理完了
            this.opeCPU((CPU)colleague);
        }
    }
    /**
     * 處理光碟機讀取數據過後與其他對象的交互
     * @param cd 光碟機同事對象
     */
    private void opeCDDriverReadData(CDDriver cd){
        //1:先獲取光碟機讀取的數據
        String data = cd.getData();
        //2:把這些數據傳遞給CPU進行處理
        this.cpu.executeData(data);
    }
    /**
     * 處理CPU處理完數據後與其他對象的交互
     * @param cpu CPU同事類
     */
    private void opeCPU(CPU cpu){
        //1:先獲取CPU處理過後的數據
        String videoData = cpu.getVideoData();
        String soundData = cpu.getSoundData();
        //2:把這些數據傳遞給顯卡和音效卡展示出來
        this.videoCard.showData(videoData);
        this.soundCard.soundData(soundData);
    }
    
}


----------
public class Client {
    public static void main(String[] args) {
        //1:創建中介者——主板對象
        MotherBoard mediator = new MotherBoard();
        //2:創建同事類
        CDDriver cd = new CDDriver(mediator);
        CPU cpu = new CPU(mediator);
        VideoCard vc = new VideoCard(mediator);
        SoundCard sc = new SoundCard(mediator);
        //3:讓中介者知道所有的同事
        mediator.setCdDriver(cd);
        mediator.setCpu(cpu);
        mediator.setVideoCard(vc);
        mediator.setSoundCard(sc);
        
        //4:開始看電影,把光碟放入光碟機,光碟機開始讀盤
        cd.readCD();
    }
}

理解中介者模式

認識中介者模式

1:中介者模式的功能
中介者的功能非常簡單,就是封裝對象之間的交互。如果一個對象的操作會引起其它相關對象的變化,或者是某個操作需要引起其它對象的後續或連帶操作,而這個對象又不希望自己來處理這些關係,那麼就可以找中介者,把所有的麻煩扔給它,只在需要的時候通知中介者,其它的就讓中介者去處理就可以了。
反過來,其它的對象在操作的時候,可能會引起這個對象的變化,也可以這麼做。最後對象之間就完全分離了,誰都不直接跟其它對象交互,那麼相互的關係,全部被集中到中介者對象裡面了,所有的對象就只是跟中介者對象進行通信,相互之間不再有聯繫。
把所有對象之間的交互都封裝在中介者當中,無形中還得到另外一個好處,就是能夠集中的控制這些對象的交互關係,這樣有什麼變化的時候,修改起來就很方便。

2:需要Mediator介面嗎
有沒有使用Mediator介面的必要,取決於是否會提供多個不同的中介者實現。如果中介者實現只有一個的話,而且預計中也沒有需要擴展的要求,那麼就可以不定義Mediator介面,讓各個同事對象直接使用中介者實現對象;如果中介者實現不只一個,或者預計中有擴展的要求,那麼就需要定義Mediator介面,讓各個同事對象來面向中介者介面編程,而無需關心具體的中介者實現。

3:同事關係
在中介者模式中,要求這些類都要繼承相同的類,也就是說,這些對象從某個角度講是同一個類型,算是兄弟對象。
正是這些兄弟對象之間的交互關係很複雜,才產生了把這些交互關係分離出去,單獨做成中介者對象,這樣一來,這些兄弟對象就成了中介者對象眼裡的同事。

4:同事和中介者的關係
中介者對象和同事對象之間是相互依賴的 。

5:如何實現同事和中介者的通信
一種實現方式是在Mediator介面中定義一個特殊的通知介面,作為一個通用的方法,讓各個同事類來調用這個方法 。
另外一種實現方式是可以採用觀察者模式,把Mediator實現成為觀察者,而各個同事類實現成為Subject,這樣同事類發生了改變,會通知Mediator。Mediator在接到通知過後,會與相應的同事對象進行交互。

6:中介者模式的調用順序示意圖
image_1cicidgia18d21tkikd1n849hd1t.png-31.4kB

廣義中介者示例——部門與人員

1:部門和人員的關係 : 是 多對多的
2:問題的出現
想想部門和人員的功能交互,舉幾個常見的功能:
(1)部門被撤銷
(2)部門之間進行合併
(3)人員離職
(4)人員從一個部門調職到另外一個部門

想想要實現這些功能,按照前面的設計,該怎麼做呢?
(1)系統運行期間,部門被撤銷了,就意味著這個部門不存在了,可是原來這個部門下所有的人員,每個人員的所屬部門中都有這個部門呢,那麼就需要先通知所有的人員,把這個部門從它們的所屬部門中去掉,然後才可以清除這個部門。
(2)部門合併,是合併成一個新的部門呢,還是把一個部門併入到另一個部門?如果是合併成一個新的部門,那麼需要把原有的兩個部門撤銷,然後再新增一個部門;如果是把一個部門合併到另一個部門裡面,那就是撤銷掉一個部門,然後把這個部門下的人員移動到這個部門。不管是那種情況,都面臨著需要通知相應的人員進行更改這樣的問題。
(3)人員離職了,反過來就需要通知他所屬於的部門,從部門的擁有人員的記錄中去除掉這個人員。
(4)人員調職,同樣需要通知相關的部門,先從原來的部門中去除掉,然後再到新的部門中添加上。

看了上述的描述,感覺如何?
麻煩的根源在什麼地方呢?仔細想想,對了,麻煩的根源就在於部門和人員之間的耦合,這樣導致操作人員的時候,需要操作所有相關的部門,而操作部門的時候又需要操作所有相關的人員,使得部門和人員攪和在了一起。

3:中介者來解決
找到了根源就好辦了,採用中介者模式,引入一個中介者對象來管理部門和人員之間的關係,就能解決這些問題了。
如果採用標準的中介者模式,想想上面提出的那些問題點吧,就知道實現起來會很彆扭。因此採用廣義的中介者來解決,這樣部門和人員就完全解耦了,也就是說部門不知道人員,人員也不知道部門,它們完全分開,它們之間的關係就完全由中介者對象來管理了。

/**
 *  描述部門和人員關係的類
 */
public class DepUserModel {
    /**
     * 用於部門和人員關係的編號,用做主鍵
     */
    private String depUserId;
    /**
     * 部門的編號
     */
    private String depId;
    /**
     * 人員的編號
     */
    private String userId;
    public String getDepUserId() {
        return depUserId;
    }
    public void setDepUserId(String depUserId) {
        this.depUserId = depUserId;
    }
    public String getDepId() {
        return depId;
    }
    public void setDepId(String depId) {
        this.depId = depId;
    }
    public String getUserId() {
        return userId;
    }
    public void setUserId(String userId) {
        this.userId = userId;
    }
}


----------
/**
 * 部門類
 */
public class Dep{
    /**
     * 描述部門編號
     */
    private String depId;
    /**
     * 描述部門名稱
     */
    private String depName;
    public String getDepId() {
        return depId;
    }
    public void setDepId(String depId) {
        this.depId = depId;
    }
    public String getDepName() {
        return depName;
    }
    public void setDepName(String depName) {
        this.depName = depName;
    }
    /**
     * 撤銷部門
     * @return 是否撤銷成功
     */
    public boolean deleteDep(){
        //1:要先通過中介者去清除掉所有與這個部門相關的部門和人員的關係
        DepUserMediatorImpl mediator = DepUserMediatorImpl.getInstance();
        mediator.deleteDep(depId);
        //2:然後才能真的清除掉這個部門
        //請註意在實際開發中,這些業務功能可能會做到業務層去,
        //而且實際開發中對於已經使用的業務數據通常是不會被刪除的,
        //而是會被做為歷史數據保留
        return true;
    }
}


----------
    /**
     * 人員名稱
     */
    private String userName;
    public String getUserId() {
        return userId;
    }
    public void setUserId(String userId) {
        this.userId = userId;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    /**
     * 人員離職
     * @return 是否處理成功
     */
    public boolean dimission(){
        //1:要先通過中介者去清除掉所有與這個人員相關的部門和人員的關係
        DepUserMediatorImpl mediator = DepUserMediatorImpl.getInstance();
        mediator.deleteUser(userId);
        //2:然後才能真的清除掉這個人員
        //請註意,實際開發中,人員離職,是不會真的刪除人員記錄的,
        //通常是把人員記錄的狀態或者是刪除標記設置成已刪除,
        //只是不再參加新的業務,但是已經發生的業務記錄是不會被清除掉的
        
        return true;
    }
}


----------
/**
 * 實現部門和人員交互的中介者實現類
 * 說明:為了演示的簡潔性,只示例實現撤銷部門和人員離職的功能
 */
public class DepUserMediatorImpl{
    private static DepUserMediatorImpl mediator = new DepUserMediatorImpl();
    private DepUserMediatorImpl(){
        //調用初始化測試數據的功能
        initTestData();
    }
    public static DepUserMediatorImpl getInstance(){
        return mediator;
    }
    
    /**
     * 測試用,記錄部門和人員的關係
     */
    private Collection<DepUserModel> depUserCol = new ArrayList<DepUserModel>();
    /**
     * 初始化測試數據
     */
    private void initTestData(){
        //準備一些測試數據
        DepUserModel du1 = new DepUserModel();
        du1.setDepUserId("du1");
        du1.setDepId("d1");
        du1.setUserId("u1");        
        depUserCol.add(du1);
        
        DepUserModel du2 = new DepUserModel();
        du2.setDepUserId("du2");
        du2.setDepId("d1");
        du2.setUserId("u2");        
        depUserCol.add(du2);
        
        DepUserModel du3 = new DepUserModel();
        du3.setDepUserId("du3");
        du3.setDepId("d2");
        du3.setUserId("u3");        
        depUserCol.add(du3);
        
        DepUserModel du4 = new DepUserModel();
        du4.setDepUserId("du4");
        du4.setDepId("d2");
        du4.setUserId("u4");        
        depUserCol.add(du4);
        
        DepUserModel du5 = new DepUserModel();
        du5.setDepUserId("du5");
        du5.setDepId("d2");
        du5.setUserId("u1");        
        depUserCol.add(du5);
    }
    /**
     * 完成因撤銷部門的操作所引起的與人員的交互,需要去除相應的關係
     * @param depId 被撤銷的部門對象的編號
     * @return 是否已經正確的處理了因撤銷部門所引起的與人員的交互
     */
    public boolean deleteDep(String depId) {
        //請註意:為了演示簡單,部門撤銷後,原部門的人員怎麼處理等後續業務處理,這裡就不管了
        
        //1:到記錄部門和人員關係的集合裡面,尋找跟這個部門相關的人員
        //設置一個臨時的集合,記錄需要清除的關係對象
        Collection<DepUserModel> tempCol = new ArrayList<DepUserModel>();
        for(DepUserModel du : depUserCol){
            if(du.getDepId().equals(depId)){
                //2:需要把這個相關的記錄去掉,先記錄下來
                tempCol.add(du);
            }
        }
        //3:從關係集合裡面清除掉這些關係
        depUserCol.removeAll(tempCol);
        
        return true;
    }
    /**
     * 完成因人員離職引起的與部門的交互
     * @param userId 離職的人員的編號
     * @return 是否正確處理了因人員離職引起的與部門的交互
     */
    public boolean deleteUser(String userId) {
        //1:到記錄部門和人員關係的集合裡面,尋找跟這個人員相關的部門
        //設置一個臨時的集合,記錄需要清除的關係對象
        Collection<DepUserModel> tempCol = new ArrayList<DepUserModel>();
        for(DepUserModel du : depUserCol){
            if(du.getUserId().equals(userId)){
                //2:需要把這個相關的記錄去掉,先記錄下來
                tempCol.add(du);
            }
        }
        //3:從關係集合裡面清除掉這些關係
        depUserCol.removeAll(tempCol);
    
        return true;
    }
    /**
     * 測試用,在內部列印顯示一下一個部門下的所有人員
     * @param dep 部門對象
     */
    public void showDepUsers(Dep dep) {
        for(DepUserModel du : depUserCol){
            if(du.getDepId().equals(dep.getDepId())){
                System.out.println("部門編號="+dep.getDepId()+"下麵擁有人員,其編號是:"+du.getUserId());
            }
        }
    }
    /**
     * 測試用,在內部列印顯示一下一個人員所屬的部門
     * @param user 人員對象
     */
    public void showUserDeps(User user) {
        for(DepUserModel du : depUserCol){
            if(du.getUserId().equals(user.getUserId())){
                System.out.println("人員編號="+user.getUserId()+"屬於部門編號是:"+du.getDepId());
            }
        }
    }
    /**
     * 完成因人員調換部門引起的與部門的交互
     * @param userId 被調換的人員的編號
     * @param oldDepId 調換前的部門的編號
     * @param newDepId 調換後的部門的編號
     * @return 是否正確處理了因人員調換部門引起的與部門的交互
     */
    public boolean changeDep(String userId,String oldDepId, String newDepId) {
        //本示例不去實現了
        return false;
    }
    

    /**
     * 完成因部門合併操作所引起的與人員的交互
     * @param colDepIds 需要合併的部門的編號集合
     * @param newDep 合併後新的部門對象
     * @return 是否正確處理了因部門合併操作所引起的與人員的交互
     */
    public boolean joinDep(Collection<String> colDepIds, Dep newDep) {
        //本示例不去實現了      
        return false;
    }
}


----------
public class Client {
    public static void main(String[] args) {
        DepUserMediatorImpl mediator = DepUserMediatorImpl.getInstance();
        //準備要撤銷的部門,僅僅需要一個部門編號
        Dep dep = new Dep();
        dep.setDepId("d1");
        Dep dep2 = new Dep();
        dep2.setDepId("d2");
        //準備用於測試的人員,也只需要一個人員編號
        User user = new User();
        user.setUserId("u1");
        
        //測試撤銷部門,在運行之前,輸出一下,看這個人員屬於哪些部門     
        System.out.println("撤銷部門前------------------");
        mediator.showUserDeps(user);
        
        //真正執行業務,撤銷這個部門
        dep.deleteDep();
        
        //再次輸出一下,看這個人員屬於哪些部門
        System.out.println("撤銷部門後------------------");
        mediator.showUserDeps(user);
        
        //測試人員離職,在運行之前,輸出一下,看這個部門下都有哪些人員
        System.out.println("---------------------------------");
        System.out.println("人員離職前------------------");
        mediator.showDepUsers(dep2);
        
        //真正執行業務,人員離職
        user.dimission();
        
        //再次輸出一下,看這個部門下都有哪些人員
        System.out.println("人員離職後------------------");
        mediator.showDepUsers(dep2);
    }
}

中介者模式的優缺點

1:鬆散耦合
2:集中控制交互
3:多對多變成一對多
4:過度集中化

思考中介者模式

中介者模式的本質

封裝交互

何時選用中介者模式

1:如果一組對象之間的通信方式比較複雜,導致相互依賴、結構混亂,可以採用中介者模式,把這些對象相互的交互管理起來,各個對象都只需要和中介者交互,從而使得各個對象鬆散耦合,結構也更清晰易懂
2:如果一個對象引用很多的對象,並直接跟這些對象交互,導致難以復用該對象。可以採用中介者模式,把這個對象跟其它對象的交互封裝到中介者對象裡面,這個對象就只需要和中介者對象交互就可以了


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 我當時就想咋回事呢 明明函數是定義在Animation裡面的 方法也是由它調用的 所以this應該指向的是Animation呀 於是乎我就繼續往下看 看打了 奧,明白了 setTimeout 和 setInterval 一般都是這麼寫 timer=setTimeout(function(){},10 ...
  • 我們在學習es6的時候會遇到一個神奇的語法 一個括弧和一個箭頭就可以實現一個函數,有時遇到參數時只傳參數就行甚至都不用寫括弧,看似簡單其實跟我們在es5中的函數是一樣的有時會改變我們this的指向。下麵我們來看一下箭頭函數我們先來按常規語法定義函數: 該函數使用箭頭函數可以使用僅僅一行代碼搞定! 是 ...
  • 聖杯模式是Javascript中用來實現繼承的一種方法,它的簡單形式如下所示 這種聖杯模式的本質在於,中間生成了一個對象,起到了隔離的作用,今後為Son.prototype添加屬性時,全部都會加在這個對象裡面,所以不會對父級產生影響。 而向上查找是沿著__proto__查找,可以順利查找到父級的屬性 ...
  • 宿主對象即瀏覽器提供的對象,主要包括DOM對象和BOM對象。 一、DOM源起 1.SGML、XML和XHTML SGML(標準通用標記語言)是定義使用標簽來表示數據的標記語言的語法。 - 標簽由一個小於號和一個大於號之間的文本組成,如<title> - 標簽分為起始標簽和結束標簽,分別表示一個特定區 ...
  • 一、跨站腳本攻擊(XSS) 跨站腳本攻擊是指通過存在安全漏洞的Web網站註冊用戶的瀏覽器運行非法的HTML標簽或JavaScript進行的一種攻擊。動態創建的HTML部分有可能隱藏著安全漏洞。就這樣,當攻擊者編寫腳本,設下陷阱,用戶在自己的瀏覽器上運行時,一不小心就會受到被動攻擊。 跨站腳本攻擊有可 ...
  • 公司這幾天項目很緊張,然後一直有各種亂七八糟的事,突然說要整個搜索的功能,第一時間想到的就是用php的模糊搜索,但是性能耗的很大,並且調取出的數據的速度賊慢,在百度上找到一個通過js來搜索的功能分享給大家。 這個是頁面 出來後的效果: 頁面代碼: js代碼 php只做了輸出數據所以在這裡就不放出來了 ...
  • Web Worker SharedWorker Service Worker ...
  • 1.DOM簡介 當網頁被載入時,瀏覽器會創建頁面的文檔對象模型,即DOM(Document Object Model)。 2.DOM操作HTML 2.1 改變HTML輸出流 不要在文檔載入完成之後使用document.write()。會覆蓋該文檔 2.2 尋找元素 通過id找到HTML元素 通過標簽 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...