觀察者模式的應用:Winform窗體之間傳值

觀察者模式的應用:Winform窗體傳值

觀察者模式的概念:git

定義了對象之間的一對多依賴,這樣一來,當一個對象改變狀態時,它的全部依賴者都會收到通知並更新。c#

今天咱們就學着用一下這個觀察者模式,先想象下這個場景:當一個窗體(主窗體)內的值發生變化時,另外幾個窗體內的值也會發生相應的變化。這個最簡單的實現方式是,在子窗體類內建立一個公共方法,在主窗體內建立子窗體的實例。當值發生變化時調用子窗體的公共方法。還有一種簡單方法是用靜態屬性,至關於全局變量,這個只能針對小型應用。第一種有一個缺點,當增長子窗體時,咱們須要更改主窗體類的代碼。沒法實現動態地增長刪除對子窗體類中值的更新。這時能夠引入觀察者模式。
咱們先建立一個winform項目,添加FrmMain,FrmSub1,FrmSub2三個窗體,每一個窗體都添加一個textbox文本框,實現當主窗體中的文本框值發生變化時,其餘兩個子窗體的值也會發生相應的變化。這裏咱們參考《Head First設計模式》,先設計發佈者和訂閱者(這裏我感受仍是叫比較順口)。代碼以下:設計模式

public interface ISubject
 {
     /// <summary>
     /// 註冊訂閱者
     /// </summary>
     /// <param name="observer"></param>
     void RegisterObserver(IObserver observer);

     /// <summary>
     /// 刪除訂閱者
     /// </summary>
     /// <param name="observer"></param>
     void RemoveObserver(IObserver observer);

     /// <summary>
     /// 通知訂閱者
     /// </summary>
     void NotifyObservers();
 }

public interface IObserver
{
    /// <summary>
    /// 觀察者對發佈者的響應方法
    /// </summary>
    /// <param name="message"></param>
    void Update(string message);
}

修改FrmMain類,使其實現ISubject接口,再給文本框增長change事件,代碼以下:this

public partial class FrmMain : Form, ISubject
{
    private string Message { get; set; }
    private List<IObserver> _observers = new List<IObserver>();


    public FrmMain()
    {
        InitializeComponent();
    }


    private void FrmMain_Load(object sender, EventArgs e)
    {
        FrmSub1 frmSub1 = new FrmSub1(this);
        FrmSub2 frmSub2 = new FrmSub2(this);
        frmSub1.Show();
        frmSub2.Show();
    }

    /// <summary>
    /// 文本框改變事件,調用通知訂閱者方法
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void txtMain_TextChanged(object sender, EventArgs e)
    {
        this.Message = txtMain.Text;
        NotifyObservers();
    }

    /// <summary>
    /// 註冊訂閱者
    /// </summary>
    /// <param name="observer"></param>
    public void RegisterObserver(IObserver observer)
    {
        _observers.Add(observer);
    }

    /// <summary>
    /// 移除訂閱者
    /// </summary>
    /// <param name="observer"></param>
    public void RemoveObserver(IObserver observer)
    {
        _observers.Remove(observer);
    }

    /// <summary>
    /// 通知訂閱者
    /// </summary>
    public void NotifyObservers()
    {
        foreach (IObserver observer in _observers)
        {
            observer.Update(Message);
        }
    }
}

子窗體類(訂閱者)的代碼以下:設計

public partial class FrmSub1 : Form,IObserver
{
    public FrmSub1(ISubject subject)
    {
        InitializeComponent();
        //註冊
        subject.RegisterObserver(this);
    }
    //當發佈者事件發生時,訂閱者須要執行的方法
    public void Update(string message,bool isShown)
    {
       txtSub.Text = message;
    }
}

上面能夠看到FrmMain又依賴了FrmSub1和FrmSub2,其實這是須要另外一個方法Show()。不過爲表現出高層不依賴底層,咱們改掉代碼,在NotifyObservers(bool isShown)方法中加入對子窗體是否show的判斷,從而實現了避免FrmMain依賴FrmSub1,FrmSub2
FrmMain類的代碼:code

public partial class FrmMain : Form, ISubject
{
    private string Message { get; set; }
    private List<IObserver> _observers = new List<IObserver>();


    public FrmMain()
    {
        InitializeComponent();
    }


    private void FrmMain_Load(object sender, EventArgs e)
    {
        //FrmSub1 frmSub1 = new FrmSub1(this);
        //FrmSub2 frmSub2 = new FrmSub2(this);
        //frmSub1.Show();
        //frmSub2.Show();
        //這裏咱們使用了方法,擺脫了對子窗體的直接依賴
        NotifyObservers(false);
    }

    /// <summary>
    /// 文本框改變事件,調用通知訂閱者方法
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void txtMain_TextChanged(object sender, EventArgs e)
    {
        this.Message = txtMain.Text;
        NotifyObservers(true);
    }

    /// <summary>
    /// 註冊訂閱者
    /// </summary>
    /// <param name="observer"></param>
    public void RegisterObserver(IObserver observer)
    {
        _observers.Add(observer);
    }

    /// <summary>
    /// 移除訂閱者
    /// </summary>
    /// <param name="observer"></param>
    public void RemoveObserver(IObserver observer)
    {
        _observers.Remove(observer);
    }

    /// <summary>
    /// 通知訂閱者
    /// </summary>
    public void NotifyObservers(bool isShown)
    {

        foreach (IObserver observer in _observers)
        {
            observer.Update(Message,isShown);
        }
    }

}

子窗體類的代碼:orm

public partial class FrmSub1 : Form,IObserver
{
    public FrmSub1(ISubject subject)
    {
        InitializeComponent();
        subject.RegisterObserver(this);
    }

    //這裏對Update作了改變,isShown爲true,表示事件觸發時子窗體已經顯示
    public void Update(string message,bool isShown)
    {
        if (isShown)
        {
            txtSub.Text = message;
        }
        else
        {
            this.Show();
        }

    }
}
[STAThread]
static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    FrmMain frmMain = new FrmMain();
    FrmSub1 frmSub1 = new FrmSub1(frmMain);
    FrmSub2 frmSub2 = new FrmSub2(frmMain);
    Application.Run(frmMain);
}

完整源代碼參考:https://gitee.com/Alexander360/ProDotnetDesignPatternFramework45server

相關文章
相關標籤/搜索