激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - C# - C# 設(shè)計模式系列教程-觀察者模式

C# 設(shè)計模式系列教程-觀察者模式

2021-11-23 15:00Wang Juqiang C#

將一個系統(tǒng)分割成一個一些類相互協(xié)作的類有一個不好的副作用,那就是需要維護(hù)相關(guān)對象間的一致性。我們不希望為了維持一致性而使各類緊密耦合,這樣會給維護(hù)、擴(kuò)展和重用都帶來不便。觀察者就是解決這類的耦合關(guān)系的。

1. 概述

  有時被稱作發(fā)布/訂閱模式,觀察者模式定義了一種一對多的依賴關(guān)系,讓多個觀察者對象同時監(jiān)聽某一個主題對象。這個主題對象在狀態(tài)發(fā)生變化時,會通知所有觀察者對象,使它們能夠自動更新自己。

2. 解決的問題

  將一個系統(tǒng)分割成一個一些類相互協(xié)作的類有一個不好的副作用,那就是需要維護(hù)相關(guān)對象間的一致性。我們不希望為了維持一致性而使各類緊密耦合,這樣會給維護(hù)、擴(kuò)展和重用都帶來不便。觀察者就是解決這類的耦合關(guān)系的。

3. 模式中的角色

  3.1 抽象主題(subject):它把所有觀察者對象的引用保存到一個聚集里,每個主題都可以有任何數(shù)量的觀察者。抽象主題提供一個接口,可以增加和刪除觀察者對象。

  3.2 具體主題(concretesubject):將有關(guān)狀態(tài)存入具體觀察者對象;在具體主題內(nèi)部狀態(tài)改變時,給所有登記過的觀察者發(fā)出通知。

  3.3 抽象觀察者(observer):為所有的具體觀察者定義一個接口,在得到主題通知時更新自己。

  3.4 具體觀察者(concreteobserver):實現(xiàn)抽象觀察者角色所要求的更新接口,以便使本身的狀態(tài)與主題狀態(tài)協(xié)調(diào)。

4. 模式解讀

  4.1 觀察者模式的類圖  

C# 設(shè)計模式系列教程-觀察者模式

  4.2 觀察者模式的代碼

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
/// <summary>
/// 抽象主題類
/// </summary>
public abstract class subject
{
private ilist<observer> observers = new list<observer>();
 
/// <summary>
/// 增加觀察者
/// </summary>
/// <param name="observer"></param>
public void attach(observer observer)
{
 observers.add(observer);
}
 
/// <summary>
/// 移除觀察者
/// </summary>
/// <param name="observer"></param>
public void detach(observer observer)
{
 observers.remove(observer);
}
 
/// <summary>
/// 向觀察者(們)發(fā)出通知
/// </summary>
public void notify()
{
 foreach (observer o in observers)
 {
 o.update();
 }
}
}
 
/// <summary>
/// 抽象觀察者類,為所有具體觀察者定義一個接口,在得到通知時更新自己
/// </summary>
public abstract class observer
{
public abstract void update();
}
 
/// <summary>
/// 具體觀察者或具體通知者,將有關(guān)狀態(tài)存入具體觀察者對象;在具體主題的內(nèi)部狀態(tài)改變時,給所有登記過的觀察者發(fā)出通知。具體主題角色通常用一個具體子類實現(xiàn)。
/// </summary>
public class concretesubject : subject
{
private string subjectstate;
 
/// <summary>
/// 具體觀察者的狀態(tài)
/// </summary>
public string subjectstate
{
 get { return subjectstate; }
 set { subjectstate = value; }
}
}
 
/// <summary>
/// 具體觀察者,實現(xiàn)抽象觀察者角色所要求的更新接口,已是本身狀態(tài)與主題狀態(tài)相協(xié)調(diào)
/// </summary>
public class concreteobserver : observer
{
private string observerstate;
private string name;
private concretesubject subject;
 
/// <summary>
/// 具體觀察者用一個具體主題來實現(xiàn)
/// </summary>
public concretesubject subject
{
 get { return subject; }
 set { subject = value; }
}
 
public concreteobserver(concretesubject subject, string name)
{
 this.subject = subject;
 this.name = name;
}
 
/// <summary>
/// 實現(xiàn)抽象觀察者中的更新操作
/// </summary>
public override void update()
{
 observerstate = subject.subjectstate;
 console.writeline("the observer's state of {0} is {1}", name, observerstate);
}
}

  4.3 客戶端代碼

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class program
{
static void main(string[] args)
{
 // 具體主題角色通常用具體自來來實現(xiàn)
 concretesubject subject = new concretesubject();
 
 subject.attach(new concreteobserver(subject, "observer a"));
 subject.attach(new concreteobserver(subject, "observer b"));
 subject.attach(new concreteobserver(subject, "observer c"));
 
 subject.subjectstate = "ready";
 subject.notify();
 
 console.read();
}
}


  運(yùn)行結(jié)果

C# 設(shè)計模式系列教程-觀察者模式

5. 模式總結(jié)

  5.1 優(yōu)點

    5.1.1 觀察者模式解除了主題和具體觀察者的耦合,讓耦合的雙方都依賴于抽象,而不是依賴具體。從而使得各自的變化都不會影響另一邊的變化。

  5.2 缺點

    5.2.1 依賴關(guān)系并未完全解除,抽象通知者依舊依賴抽象的觀察者。

  5.3 適用場景

    5.3.1 當(dāng)一個對象的改變需要給變其它對象時,而且它不知道具體有多少個對象有待改變時。

    5.3.2 一個抽象某型有兩個方面,當(dāng)其中一個方面依賴于另一個方面,這時用觀察者模式可以將這兩者封裝在獨(dú)立的對象中使它們各自獨(dú)立地改變和復(fù)用。

 

6. 模式引申,應(yīng)用c#中的事件委托來徹底解除通知者和觀察者之間的耦合。

   6.1 關(guān)于委托的定義:委托是一種引用方法的類型。一旦為委托分配了方法,委托將與該方法有相同的行為。委托方法可以像其它任何方法一樣,具有參數(shù)和返回值。委托可以看作是對函數(shù)(方法)的的抽象,是函數(shù)的“類”,委托的實例代表一個(或多個)具體的函數(shù),它可以是多播的。

   6.2 關(guān)于事件:事件基于委托,為委托提供了一種發(fā)布/訂閱機(jī)制。事件的訂閱與取消與我們剛才講的觀察者模式中的訂閱與取消類似,只是表現(xiàn)形式有所不同。在觀察者模式中,訂閱使用方法attach()來進(jìn)行;在事件的訂閱中使用“+=”。類似地,取消訂閱在觀察者模式中用dettach(),而事件的取消用“-=”。

 

7. 下面例子分別用觀察者模式,事件機(jī)制來實現(xiàn)

  7.1 實例描述:客戶支付了訂單款項,這時財務(wù)需要開具發(fā)票,出納需要記賬,配送員需要配貨。

  7.2 觀察者模式的實現(xiàn)

    7.2.1 類圖

C# 設(shè)計模式系列教程-觀察者模式

    7.2.2 代碼實現(xiàn)

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/// <summary>
/// 抽象觀察者
/// </summary>
public interface isubject
{
void notify();
}
 
/// <summary>
/// 工作崗位,作為這里的觀察者的抽象
/// </summary>
public abstract class jobstation
{
public abstract void update();
}
 
/// <summary>
/// 具體主題,這里是客戶
/// </summary>
public class customer : isubject
{
private string customerstate;
 
private ilist<jobstation> observers = new list<jobstation>();
 
/// <summary>
/// 增加觀察者
/// </summary>
/// <param name="observer"></param>
public void attach(jobstation observer)
{
 this.observers.add(observer);
}
 
/// <summary>
/// 移除觀察者
/// </summary>
/// <param name="observer"></param>
public void detach(jobstation observer)
{
 this.observers.remove(observer);
}
 
/// <summary>
/// 客戶狀態(tài)
/// </summary>
public string customerstate
{
 get { return customerstate; }
 set { customerstate = value; }
}
 
public void notify()
{
 foreach (jobstation o in observers)
 {
 o.update();
 }
}
}
 
/// <summary>
/// 會計
/// </summary>
public class accountant : jobstation
{
private string accountantstate;
private customer customer;
 
public accountant(customer customer)
{
 this.customer = customer;
}
 
/// <summary>
/// 更新狀態(tài)
/// </summary>
public override void update()
{
 if (customer.customerstate == "已付款")
 {
 console.writeline("我是會計,我來開具發(fā)票。");
 accountantstate = "已開發(fā)票";
 }
}
}
 
/// <summary>
/// 出納
/// </summary>
public class cashier : jobstation
{
private string cashierstate;
private customer customer;
 
public cashier(customer customer)
{
 this.customer = customer;
}
 
public override void update()
{
 if (customer.customerstate == "已付款")
 {
 console.writeline("我是出納員,我給登記入賬。");
 cashierstate = "已入賬";
 }
}
}
 
/// <summary>
/// 配送員
/// </summary>
public class dilliveryman : jobstation
{
private string dillivierymanstate;
private customer customer;
 
public dilliveryman(customer customer)
{
 this.customer = customer;
}
 
public override void update()
{
 if (customer.customerstate == "已付款")
 {
 console.writeline("我是配送員,我來發(fā)貨。");
 dillivierymanstate = "已發(fā)貨";
 }
}
}

 

    7.2.3 客戶端代碼

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class program
{
static void main(string[] args)
{
 
 customer subject = new customer();
 
 subject.attach(new accountant(subject));
 subject.attach(new cashier(subject));
 subject.attach(new dilliveryman(subject));
 
 subject.customerstate = "已付款";
 subject.notify();
 
 console.read();
}
}

 


    運(yùn)行結(jié)果:

    我是會計,我來開具發(fā)票。
    我是出納員,我給登記入賬。
    我是配送員,我來發(fā)貨。

 

  7.3 事件實現(xiàn)

    7.3.1 類圖

C# 設(shè)計模式系列教程-觀察者模式

    通過類圖來看,觀察者和主題之間已經(jīng)不存在任何依賴關(guān)系了。

    7.3.2 代碼實現(xiàn)

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
/// <summary>
/// 抽象主題
/// </summary>
public interface isubject
{
void notify();
}
 
/// <summary>
/// 聲明委托
/// </summary>
public delegate void customereventhandler();
 
/// <summary>
/// 具體主題
/// </summary>
public class customer : isubject
{
private string customerstate;
 
// 聲明一個委托事件,類型為 customereventhandler
public event customereventhandler update;
 
public void notify()
{
 if (update != null)
 {
 // 使用事件來通知給訂閱者
 update();
 }
}
 
public string customerstate
{
 get { return customerstate; }
 set { customerstate = value; }
}
}
 
/// <summary>
/// 財務(wù),已經(jīng)不需要實現(xiàn)抽象的觀察者類,并且不用引用具體的主題
/// </summary>
public class accountant
{
private string accountantstate;
 
public accountant()
{ }
 
/// <summary>
/// 開發(fā)票
/// </summary>
public void giveinvoice()
{
 console.writeline("我是會計,我來開具發(fā)票。");
 accountantstate = "已開發(fā)票";
}
}
 
/// <summary>
/// 出納,已經(jīng)不需要實現(xiàn)抽象的觀察者類,并且不用引用具體的主題
/// </summary>
public class cashier
{
private string cashierstate;
 
public void recoded()
{
 console.writeline("我是出納員,我給登記入賬。");
 cashierstate = "已入賬";
}
}
 
/// <summary>
/// 配送員,已經(jīng)不需要實現(xiàn)抽象的觀察者類,并且不用引用具體的主題
/// </summary>
public class dilliveryman
{
private string dillivierymanstate;
 
public void dilliver()
{
 console.writeline("我是配送員,我來發(fā)貨。");
 dillivierymanstate = "已發(fā)貨";
}
}

 

    7.3.3 客戶端代碼

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class program
{
static void main(string[] args)
{
 
 customer subject = new customer();
 
 accountant accountant = new accountant();
 cashier cashier = new cashier();
 dilliveryman dilliveryman = new dilliveryman();
 
 // 注冊事件
 subject.update += accountant.giveinvoice;
 subject.update += cashier.recoded;
 subject.update += dilliveryman.dilliver;
 
 /*
 * 以上寫法也可以用下面代碼來替換
 subject.update += new customereventhandler(accountant.giveinvoice);
 subject.update += new customereventhandler(cashier.recoded);
 subject.update += new customereventhandler(dilliveryman.dilliver);
 */
 
 subject.customerstate = "已付款";
 subject.notify();
 
 console.read();
}
}


    運(yùn)行結(jié)果

    我是會計,我來開具發(fā)票。
    我是出納員,我給登記入賬。
    我是配送員,我來發(fā)貨。

延伸 · 閱讀

精彩推薦
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25
主站蜘蛛池模板: 男女羞羞的视频 | 黄色毛片免费看 | 成人9禁啪啪无遮挡免费 | 精品不卡 | 中文字幕在线观看视频一区 | chinesehdxxxx无套 久久另类视频 | 999久久久精品 | 成年毛片 | 俄罗斯16一20sex牲色另类 | 精品国产91久久久久 | 免费毛片在线视频 | 国产免费视频一区二区裸体 | 日韩精品免费一区二区三区 | 看毛片的网址 | 国产精品久久久久久久久久三级 | av大全在线免费观看 | 欧美一级三级在线观看 | 欧美一级做性受免费大片免费 | 国产精品视频一区二区噜噜 | av电影在线观看网址 | 91精品一区二区综合在线 | av成人在线免费观看 | 国产69精品99久久久久久宅男 | 国产精品久久久久久久不卡 | 人人看人人艹 | 亚洲视频在线网 | 久久蜜桃精品一区二区三区综合网 | 免费观看的毛片手机视频 | 欧美一级无毛 | 久久午夜神器 | 91精品国产成人 | 久久久久中精品中文字幕19 | 亚洲成人激情av | 亚洲免费观看视频 | 男女视频免费看 | 亚州精品在线视频 | 中文字幕网站在线 | 欧美视频一区二区 | 视频国产一区二区 | 久久精品电影网 | 成人免费久久网 |