入門設計模式之中介者模式(十八)

一、描述

        對象類與對象類之間的交互通信統一由另外一箇中介類來控制 ,對象通過中介類對其他對象交互,中介類起着控制器的作用。

二、優劣勢


優點:降低類與類之間的耦合性,對象與對象之間不再相互引用,把類與類之間的交互抽離出來方便擴展。
缺點:關係過於複雜的話,如對象與對象類交互功能比較多時,中介類將異常龐大,不利於後期維護。

三、需求

      實現房東與租客2個人之間的交流,主要有說話和聆聽。


四、不使用設計模式

        都不考慮設計了,直接擼代碼。

        3個類,

        Person.cs  -人基類  

        Landlord.cs  -房東類  

        Tenant.cs  -租客類

// 人基類
public class Person
{
    public string name;
    public Person(string str)
    {
        name = str;
    }
    public virtual void Talk(Person person, string str)
    {

    }

    public virtual void Listen(Person person, string str)
    {

    }
}

//房東類
public class Landlord : Person
{
    public Landlord(string str) : base(str)
    {

    }
    public override void Talk(Person person, string str)
    {
        Debug.Log("房東-" + name + "發出消息:" + str);
        person.Listen(this, str);
    }

    public override void Listen(Person person, string str)
    {
        Debug.Log("房東-" + name + "收到來自"+person.name+"的消息:" + str);
    }
}

//租客類
public class Tenant : Person
{
    public Tenant(string str) : base(str)
    {

    }
    public override void Talk(Person person, string str)
    {
        Debug.Log("租客-" + name + "發出消息:" + str);
        person.Listen(this, str);
    }

    public override void Listen(Person person, string str)
    {
        Debug.Log("租客-" + name + "收到來自" + person.name + "的消息:" + str);
    }
}

//客戶端調用
public static void main(string[] args)
{
    Landlord landlord = new Landlord("李姐");
    Tenant tenant = new Tenant("小趙");
    tenant.Talk(landlord, "房東啊,月租多少?");
    landlord.Talk(tenant, "就一千三,很便宜的!");
}

運行結果

小結:每次房東或者租客要說話時,都得把接收者對象傳遞過去,在說話方法時調用接收對象的listen方法,此處爲耦合部分。

 

五、使用設計模式

        通過添加一箇中介,房東與租客的通話都交給他來處理,這樣房東與租客就不需要互相認識再去溝通了。

        5個類,

        Person.cs  -人基類  

        Landlord.cs  -房東類  

        Tenant.cs  -租客類

        Mediator   -中介者基類

        PlayerMediator  -中介類實現

// 人基類
public class Person
{
    public string name;
    protected Mediator mediator;
    
    public Person(string str)
    {
        name = str;
    }

    public void SetMediator(Mediator m)
    {
        mediator = m;
    }

    public virtual void Talk(string str)
    {

    }

    public virtual void Listen(Person person, string str)
    {

    }
}

//房東類
public class Landlord : Person
{     
    public Landlord(string str) : base(str)
    {

    }
    public override void Talk(string str)
    {
        Debug.Log("房東-" + name + "發出消息:" + str);    
        mediator.Listen(this,str);
    }

    public override void Listen(Person person, string str)
    {
        Debug.Log("房東-" + name  + "收到來自" + person.name + "的消息:" + str);
    }
}

//租客類
public class Tenant : Person
{ 
    public Tenant(string str) : base(str)
    {

    }
    public override void Talk(string str)
    {
        Debug.Log("租客-" + name + "發出消息:" + str);
        mediator.Listen(this, str);
    }

    public override void Listen(Person person, string str)
    {
        Debug.Log("租客-" + name + "收到來自" + person.name + "的消息:" + str);
    }
}

//中介基類
public abstract class Mediator
{
    public abstract void Listen(Person person, string str);
}

//中介者具體實現
public class PlayerMediator : Mediator
{
    private Tenant tenant;//租客
    private Landlord landlord;//房東

    public void SetTenant(Tenant t)
    {
        tenant = t;
    }
    public void SetLandlord(Landlord l)
    {
        landlord = l;
    }

    //根據傳過來的對象來決定接收者
    public override void Listen(Person person, string str)
    {
        if (person== tenant)
        {
            landlord.Listen(person,str);
        }
        else if (person == landlord)
        {
            tenant.Listen(person, str);
        }
    }
}

//客戶端調用
public static void main(string[] args)
{
     Landlord landlord = new Landlord("李姐");
     Tenant tenant = new Tenant("小趙");

     PlayerMediator playerMediator = new PlayerMediator();
     playerMediator.SetLandlord(landlord);
     playerMediator.SetTenant(tenant);

     landlord.SetMediator(playerMediator);
     tenant.SetMediator(playerMediator);

     tenant.Talk("房東啊,月租多少?");
     landlord.Talk("就一千三,很便宜的!");
}

運行結果

小結:房東與租客在說話時不需要在他talk裏去處理調用接收者的listent方法了,而是由其持有的中介對象PlayerMediator去處理這些事,解耦步驟就在這點上,剝離了與接收者的listent通信,雖然客戶端調用的步驟多了一些賦值步驟,但是面向對象就是這樣, 不要介意這個,還是很穩的放心。

六、設計圖

通過學習,我們瞭解到了中介者模式的應用,我們把剛剛的實現方式畫出來。

七、進階例子

(1)需求:班長通知消息給每一個同學。

(2)分析:按照笨方法,班長得走到每一個人面前跟他說一遍,有幾個人就得說幾次,也就是班長類得調用無數次talk方法然後依次傳入每一個同學類對象,當不只是班長髮言,假如2個同學要說悄悄話了,那麼就變成了這樣:,如下圖。

 

爲了解決這個問題,我們引入了交流工具QQ,變成如下:

這樣是不是清晰多了,這裏的QQ就是我們的中介對象。

(3)實現代碼:

        5個類,

        Student.cs  -學生基類  

        BanZhang.cs  -班長類 

        TongXue.cs  -學生類

        Mediator   -中介者基類

        QQMediator  -中介QQ類實現

// 學生基類
public class Student
{
    public string name;
    //中介者qq對象
    protected Mediator mediator;

    public Student(string str)
    {
        name = str;
    }

    public void SetMediator(Mediator m)
    {
        mediator = m;
    }

    //在羣裏說話
    public virtual void TalkAll(string str)
    {
        mediator.TalkAll(this, str);
    }

    //跟一個人私聊,參數爲私聊對象
    public virtual void TalkOne(Student student, string str)
    {
        mediator.TalkOne(this, student, str);
    }

    public virtual void Listen(Student student, string str)
    {
        Debug.Log(name + "接收到了來自" + student.name + "的消息:" + str);
    }
}

//班長類
public class BanZhang : Student
{

    public BanZhang(string str) : base(str)
    {

    }
}

//同學類
public class TongXue : Student
{
    public TongXue(string str) : base(str)
    {

    }
}

//中介基類
public abstract class Mediator
{
    //私聊
    public abstract void TalkOne(Student talkMan, Student listentMan, string str);

    //羣聊
    public abstract void TalkAll(Student talkMan, string str);
}

//中介者QQ具體實現
public class QQMediator : Mediator
{
    //保存有參與進來qq的人員
    private List<Student> studentList;
    public QQMediator()
    {
        studentList = new List<Student>();
    }

    //添加人員到qq
    public void AddStudent(params Student[] s)
    {
        studentList.AddRange(s);
    }

    //羣聊
    public override void TalkAll(Student talkMan, string str)
    {
        if (studentList.Contains(talkMan))
        {
            foreach (Student item in studentList)
            {
                if (item != talkMan)
                {
                    item.Listen(talkMan, str);
                }
            }
        }
    }

    //私聊
    public override void TalkOne(Student talkMan, Student listentMan, string str)
    {
        if (studentList.Contains(talkMan) && studentList.Contains(listentMan))
        {
            listentMan.Listen(talkMan,str);
        }
    }
}

//客戶端調用
public static void main(string[] args)
{
    QQMediator qqediator = new QQMediator();
    BanZhang banZhang = new BanZhang("班長");
    banZhang.SetMediator(qqediator);

    TongXue tongXue1 = new TongXue("張無忌");
    tongXue1.SetMediator(qqediator);

    TongXue tongXue2 = new TongXue("趙敏");
    tongXue2.SetMediator(qqediator);

    qqediator.AddStudent(banZhang, tongXue1, tongXue2);

    //班長廣播通知消息
    banZhang.TalkAll("下午第三節課上體育!");
    //也可以這麼調用: qqediator.TalkAll(banZhang, "下午第三節課上體育!");

    Debug.Log("----------------------分割線----------------------");

    //私聊
    tongXue1.TalkOne(tongXue2, "小敏,體育課跟我玩吧");
    tongXue2.TalkOne(tongXue1, "好的哦");
    //也可以這麼調用: tongXue2.TalkOne(tongXue1,tongXue2, "下午第三節課上體育!");
}

運行結果:

八、總結

 覺得有用就留下評論吧^-^

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章