明輝手游網(wǎng)中心:是一個(gè)免費(fèi)提供流行視頻軟件教程、在線(xiàn)學(xué)習(xí)分享的學(xué)習(xí)平臺(tái)!

IssueVision 學(xué)習(xí)筆記(3)-----設(shè)計(jì)模式之OBSERVER(觀(guān)察者)模式

[摘要]這次我們來(lái)看看IssueVision中的對(duì)設(shè)計(jì)模式的應(yīng)用,IssueVision主要使用了OBSERVER(觀(guān)察者)模式和COMMAND(命令)模式.今天就來(lái)看看OBSERVER(觀(guān)察者)模式在IssueVision中的應(yīng)用,它在IssueVision中扮演著重要角色. "四人幫...
這次我們來(lái)看看IssueVision中的對(duì)設(shè)計(jì)模式的應(yīng)用,IssueVision主要使用了OBSERVER(觀(guān)察者)模式和COMMAND(命令)模式.今天就來(lái)看看OBSERVER(觀(guān)察者)模式在IssueVision中的應(yīng)用,它在IssueVision中扮演著重要角色.

"四人幫"GoF是這樣定義OBSERVER(觀(guān)察者)模式的------定義對(duì)象間的一種一對(duì)多的關(guān)系,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),所有依賴(lài)它的對(duì)象都得到通知,并被自動(dòng)更新.
從定義可以看出,OBSERVER(觀(guān)察者)模式邏輯上需要兩組對(duì)象來(lái)實(shí)現(xiàn).首先它必需要有發(fā)布者(Publish),也可稱(chēng)為被觀(guān)察的目標(biāo)(Subject)(習(xí)慣上都稱(chēng)它為目標(biāo)Subject,后面我們都稱(chēng)它作目標(biāo)Subject),另外就是訂閱者(Subscribe),習(xí)慣上稱(chēng)為觀(guān)察者(Observer).一個(gè)目標(biāo)對(duì)象對(duì)應(yīng)多個(gè)觀(guān)察者對(duì)象,目標(biāo)對(duì)象發(fā)生變化時(shí),所有在目標(biāo)對(duì)象中注冊(cè)的觀(guān)察者對(duì)象會(huì)得到通知,自動(dòng)更新自己.

在應(yīng)用程序開(kāi)發(fā)過(guò)程中,往往都要求用戶(hù)界面和業(yè)務(wù)邏輯分離,劃定清晰的界限.因?yàn)閼?yīng)用程序要求能快速的更改用戶(hù)界面并且不能對(duì)應(yīng)用程序其他部分產(chǎn)生連帶影響,而且業(yè)務(wù)邏輯也會(huì)發(fā)生變化并要求這一切變化與用戶(hù)界面無(wú)關(guān).觀(guān)察者(Observer)就是解決此問(wèn)題最常用的設(shè)計(jì)模式,它非常有助于在系統(tǒng)中各個(gè)對(duì)象之間劃分清晰的界限.

下圖最好的展示了這種形式,觀(guān)者者(observer)們(表格對(duì)象,柱狀圖對(duì)象和餅狀圖對(duì)象)都依賴(lài)數(shù)據(jù)對(duì)象Subject,所以數(shù)據(jù)對(duì)象Subject的所有改變都會(huì)通知它們.但它們互相之間并不知道對(duì)方的存在,表格對(duì)象不知道其他表格對(duì)象或者其他柱狀圖對(duì)象的存在.對(duì)于數(shù)據(jù)對(duì)象Subject可以有任何多的觀(guān)察者,這些觀(guān)察者都能在Subject對(duì)象發(fā)生改變時(shí)得到通知,使自己的狀態(tài)與Subject同步:





好吧,概念就說(shuō)這么多吧,我們來(lái)看一下OBSERVER(觀(guān)察者)模式的實(shí)現(xiàn).通用的OBSERVER(觀(guān)察者)模式的實(shí)現(xiàn)我在這就不說(shuō)了,可以參考GoF的設(shè)計(jì)模式和Java與模式等書(shū).我們就來(lái)專(zhuān)注于.NET框架中OBSERVER(觀(guān)察者)模式的實(shí)現(xiàn).

.NET框架引入了委托和事件,它們提供了更新,功能更強(qiáng)大的方法來(lái)實(shí)現(xiàn)OBSERVER(觀(guān)察者)模式.(關(guān)于委托和事件的更多內(nèi)容請(qǐng)參考相關(guān)文檔).如果你不熟悉委托和事件,實(shí)現(xiàn)OBSERVER(觀(guān)察者)模式則需要作很多工作(像在Java中實(shí)現(xiàn)那樣).下面我就以IssueVision中的實(shí)現(xiàn)來(lái)簡(jiǎn)單講述一下.

在IssueVision中Patterns文件夾下有兩個(gè)文件ISubject.cs和IObserver.cs.它們分別定義了目標(biāo)(Subject)對(duì)象和觀(guān)者者(Observer)對(duì)象的接口,代碼如下:

ISubject.cs

namespace IssueVision
{
// ISubject is a simple marker interface that supports the implementation
// of the Observer pattern in IssueVision.
public interface ISubject
{
}
}

IObserver.cs

namespace IssueVision
{
// IObserver is a simple interface that supports the implementation of the
// Observer pattern in IssueVision.
public interface IObserver
{
ISubject Subject
{
set;
}
}
}

大家可能發(fā)現(xiàn),這兩個(gè)接口幾乎為空,什么都沒(méi)有定義,那這兩個(gè)接口的作用是什么呢?其實(shí)定義這兩個(gè)接口的作用主要為編碼的"規(guī)范化",只要類(lèi)實(shí)現(xiàn)了這兩個(gè)接口任何一個(gè),那么就代表此類(lèi)就實(shí)現(xiàn)了OBSERVER(觀(guān)察者)模式,并且很明顯的知道誰(shuí)是Subject,誰(shuí)是Observer.

IssueVision中的IssueSubject組件就實(shí)現(xiàn)ISubject接口,它是IssueVision中實(shí)現(xiàn)OBSERVER(觀(guān)察者)模式最主要的部分,也是IssueVision中最最復(fù)雜的一個(gè)類(lèi).我們慢慢一點(diǎn)一點(diǎn)來(lái)分析它(當(dāng)然之分析OBSERVER(觀(guān)察者)模式相關(guān)部分):

IssueSubject.cs

public class IssueSubject : Component, ISubject

首先定義類(lèi)IssueSubject繼承自Component和ISubject,從這里和類(lèi)名可以看出,此類(lèi)是作為OBSERVER(觀(guān)察者)模式中的目標(biāo)(Subject)實(shí)現(xiàn)的.目標(biāo)(Subject)對(duì)象要求實(shí)現(xiàn)對(duì)觀(guān)察者(Observer)的注冊(cè)(Register)和通知,Component類(lèi)就是用來(lái)實(shí)現(xiàn)注冊(cè)(Register)的.大多數(shù)目標(biāo)(Subject)對(duì)象的實(shí)現(xiàn)并不是并非將觀(guān)察者(Observer)的引用直接存儲(chǔ)在自己的實(shí)例變量中,而是將此人物委托給一個(gè)單獨(dú)的對(duì)象(通常為一個(gè)容器)Component類(lèi)就是這樣一個(gè)容器,下面代碼顯示了如何用Component類(lèi)容器來(lái)存儲(chǔ)對(duì)觀(guān)察者(Observer)對(duì)象的引用注冊(cè)(Register)

public IssueSubject(IContainer Container) : this()
{
Container.Add(this);
}

我們來(lái)看一下它是如何完成注冊(cè)(Register)的,首先我們找到一個(gè)觀(guān)察者(Observer)對(duì)象的實(shí)現(xiàn),Controls/IssueTreeView 用戶(hù)控件就是一個(gè)觀(guān)察者(Observer)對(duì)象.它實(shí)現(xiàn)了IObserver接口.

Controls/IssueTreeView.cs

namespace IssueVision
{
// The IssueTreeView user control implements the view selection ui for IssueVision
public class IssueTreeView : UserControl, IObserver
{

.....
private TreeView trvViews;
private ImageList images;

private IssueSubject m_subject = null;
private const string m_fontname = "Tahoma";

private IContainer components;

public virtual ISubject Subject //ISubject接口的方法
{
set
{
m_subject = (IssueSubject)value;
.....
}
}

Pane/StaffPane用戶(hù)控件引用了此IssueTreeView,它同樣也是觀(guān)察者(Observer)對(duì)象.

Pane/StaffPane.cs

namespace IssueVision
{
public class StaffPane : UserControl, IObserver
{

....
private IssueTreeView itvViews;

private IContainer components = null;

// IObserver.Subject
public ISubject Subject
{
set
{
itvViews.Subject = (IssueSubject)value;
}
}

在MainForm.cs中調(diào)用此用戶(hù)控件代碼如下:

private IssueSubject m_issueSubject = null;

.....
m_issueSubject = new IssueSubject(this.components); //調(diào)用IssueSubject的構(gòu)造函數(shù)


paneStaff.Subject = m_issueSubject;

通過(guò)調(diào)用IssueSubject的構(gòu)造函數(shù),是此觀(guān)察者(Observer)對(duì)象注冊(cè)到了目標(biāo)(Subject)對(duì)象中.(通過(guò)容器的Container.Add())



這樣就完成了OBSERVER(觀(guān)察者)模式的第一步,觀(guān)察者(Observer)對(duì)象的注冊(cè).下面我們來(lái)看第二步,目標(biāo)(Subject)對(duì)象如何通知觀(guān)察者(Observer)對(duì)象


這就需要使用到委托和事件了.在回來(lái)看IssueSubject

IssueSubject.cs


public class IssueSubject : Component, ISubject
{

#region Delagate and Event Declarations
.......

public delegate void ConflictDataChangedEventHandler(object sender, EventArgs e);
public delegate void LookupDataChangedEventHandler(object sender, EventArgs e);

// ConflictDataChanged changes when a conflict is resolved, or new conflicts are
// detected.
public virtual event ConflictDataChangedEventHandler ConflictDataChanged;

// LookupDataChanged is raised when lookup data is downloaded from the server
public virtual event LookupDataChangedEventHandler LookupDataChanged;

......

在IssueSubject中申明委托和事件,觀(guān)察者(Observer)對(duì)象登記這些事件,那么當(dāng)IssueSubject改變后,激活一個(gè)事件,那么所有的觀(guān)察者(Observer)對(duì)象都能得到這個(gè)改變的通知,從而激活相應(yīng)的處理.

再看Controls/IssueTreeView.cs

namespace IssueVision
{
// The IssueTreeView user control implements the view selection ui for IssueVision
public class IssueTreeView : UserControl, IObserver
{

.....
private TreeView trvViews;

private IssueSubject m_subject = null;

private IContainer components;

public virtual ISubject Subject //ISubject接口的方法
{
set
{
m_subject = (IssueSubject)value;

//登記IssueSubject的事件,并交給相關(guān)方法處理事件
m_subject.LookupDataChanged += new IssueSubject.LookupDataChangedEventHandler(this.Subject_LookupDataChanged);
m_subject.ConflictDataChanged += new IssueSubject.ConflictDataChangedEventHandler(this.Subject_ConflictDataChanged);
}
}

最后,在IssueSubject中激活這些事件.

IssueSubject.cs

private void LoadIssueData()
{
.......
m_dataSet.DataSetName = "IssueSubject";

if (LookupDataChanged != null)
{
LookupDataChanged(this, EventArgs.Empty);
}
}


通過(guò)這么簡(jiǎn)單的幾個(gè)步驟,就實(shí)現(xiàn)了OBSERVER(觀(guān)察者)模式,.NET框架提供的委托和事件機(jī)制很大的簡(jiǎn)化了模式的實(shí)現(xiàn).

CopyRight © YellowWee 2004. All Right Reserved.