C#学习笔记-观察者模式

题目1:几个同事为了在上班期间偷偷看休息,做点其他的事情,就和小秘偷偷联系了一下,如果老板回来了,就麻烦小秘偷偷通知一声,这样方便大家及时变更自己的工作状态。

分析:

  根据题目分析,首先明确,肯定会有两个类:小秘类和同事类,分别描述与记录两种类型的人和行为。

  需要注意的是:小秘与同事构建联系的时候,一个小秘可能对应多位同事,所以这时需要利用List<>。

实现:

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             Secretary lady = new Secretary();
 6             StockObserver num1 = new StockObserver("A", lady);
 7             StockObserver num2 = new StockObserver("B", lady);
 8 
 9             lady.Attach(num1);
10             lady.Attach(num2);
11 
12             lady.SecretAction="boss is back";
13             lady.Notify();
14 
15             Console.Read();
16         }
17     }
18 
19     /// <summary>
20     /// 小秘
21     /// 1.记下需要联系的同事们List<StockObserver>
22     /// 2.增加需要联系的人员
23     /// 3.减少联系人员(有可能没有通知到,有可能人员辞职等)
24     /// 4.秘密通知同事,老板回来了
25     /// </summary>
26     class Secretary
27     {
28         IList<StockObserver> stockOb = new List<StockObserver>();
29         private string action;
30 
31         public string SecretAction
32         {
33             get
34             {
35                 return action;
36             }
37 
38             set
39             {
40                 action = value;
41             }
42         }
43 
44         //增加需要联系的人员
45         public void Attach(StockObserver ob)
46         {
47             stockOb.Add(ob);
48         }
49 
50         //减少需要联系的人员
51         public void Detach(StockObserver ob)
52         {
53             stockOb.Remove(ob);
54         }
55 
56         //小秘通知了同事后,同事赶紧自行更改工作状态
57         public void Notify()
58         {
59             foreach (StockObserver o in stockOb)
60                 o.Update();
61         }
62     }
63 
64     /// <summary>
65     /// 看股票的同事
66     /// 1.联系小秘,和小秘保持良好关系
67     /// 2.根据小秘的偷偷通知修改自己的工作状态
68     /// </summary>
69     class StockObserver
70     {
71         private string name;
72         private Secretary sec;
73 
74         public StockObserver(string name,Secretary sec)
75         {
76             this.name = name;
77             this.sec = sec;
78         }
79         public void Update()
80         {
81             Console.WriteLine("{0} {1} 关闭股票行情,继续工作!", sec.SecretAction, name);
82         }
83     }
View Code

 

 

 

题目2:由于同事们人数众多,所以大家休闲的方式并不一致。

分析:

  同事们的休闲方式不同,他们彼此之间存在共同点与不同点。

  他们的共同点在于都需要与小秘联系且更新工作状态,同时他们的不同点也在于更新工作状态。

  所以相同点就不需要在子类中赘述,所以通过抽象类来将不同的方法设为抽象即可。

实现:

  1     class Program
  2     {
  3         static void Main(string[] args)
  4         {
  5             Secretary lady = new Secretary();
  6             StockObserver num1 = new StockObserver("A", lady);
  7             NBAObserver num2 = new NBAObserver("B", lady);
  8 
  9             lady.Attach(num1);
 10             lady.Attach(num2);
 11 
 12             lady.SecretAction = "boss is back";
 13             lady.Notify();
 14 
 15             Console.Read();
 16         }
 17     }
 18 
 19     /// <summary>
 20     /// 小秘
 21     /// 1.记下需要联系的同事们List<StockObserver>
 22     /// 2.增加需要联系的人员
 23     /// 3.减少联系人员(有可能没有通知到,有可能人员辞职等)
 24     /// 4.秘密通知同事,老板回来了
 25     /// </summary>
 26     class Secretary
 27     {
 28         IList<Observers> observers = new List<Observers>();
 29         private string action;
 30 
 31         public string SecretAction
 32         {
 33             get
 34             {
 35                 return action;
 36             }
 37 
 38             set
 39             {
 40                 action = value;
 41             }
 42         }
 43 
 44         //增加需要联系的人员
 45         public void Attach(Observers ob)
 46         {
 47             observers.Add(ob);
 48         }
 49 
 50         //减少需要联系的人员
 51         public void Detach(Observers ob)
 52         {
 53             observers.Remove(ob);
 54         }
 55 
 56         //小秘通知了同事后,同事赶紧自行更改工作状态
 57         public void Notify()
 58         {
 59             foreach (Observers o in observers)
 60                 o.Update();
 61         }
 62     }
 63 
 64     /// <summary>
 65     /// 观察者类
 66     /// 抽象类
 67     /// 偷偷玩的同事的状态都不同,他们的共同点就是1.与小秘联系,2.更新工作状态
 68     /// 不同点在于更新状态前不同,所以更新工作状态设置为抽象方法即可
 69     /// </summary>
 70     abstract class Observers
 71     {
 72         protected string name;
 73         protected Secretary sec;
 74 
 75         public  Observers(string name,Secretary sec)
 76         {
 77             this.name = name;
 78             this.sec = sec;
 79         }
 80 
 81         public abstract void Update();
 82     }
 83 
 84 
 85     /// <summary>
 86     /// 看股票的同事
 87     /// 继承于观察者类
 88     /// 根据小秘的偷偷通知修改自己的工作状态
 89     /// </summary>
 90     class StockObserver:Observers
 91     {
 92         public StockObserver(string name, Secretary sec) 
 93             : base(name, sec)
 94         {
 95         }
 96 
 97         public override void  Update()
 98         {
 99             Console.WriteLine("{0} {1} 关闭股票行情,继续工作!", sec.SecretAction,name);
100         }
101     }
102 
103     /// <summary>
104     /// 看NBA节目的同事
105     /// 继承于观察者类
106     /// 根据小秘的偷偷通知修改自己的工作状态
107     /// </summary>
108     class NBAObserver : Observers
109     {
110         public NBAObserver(string name, Secretary sec) 
111             : base(name, sec)
112         {
113         }
114 
115         public override void Update()
116         {
117             Console.WriteLine("{0} {1} 关闭NBA直播,继续工作!", sec.SecretAction, name);
118         }
119     }
View Code

 

 

 

题目3:如果小秘突然有事情变得特别忙的时候,就没有了通知者,而此刻老板突然回来了,所以老板本身就变成了临时的通知者。

分析:

  老板本身变成了临时的通知者,虽然这个故事很不幸,但是客观分析,此刻老板的作用于小秘是一样的,所以老板应该和小秘继承于同一种父类。

  由于老板需要与观察者联系,而此刻的观察者已是抽象类,所以老板的父类不能再为抽象类了。

  原因如下:

  

  故此,老板和小秘只能通过接口来实现了。

实现:

  1     class Program
  2     {
  3         static void Main(string[] args)
  4         {
  5             Boss boss = new Boss();
  6 
  7 
  8             Secretary lady = new Secretary();
  9             StockObserver num1 = new StockObserver("A", lady);
 10             NBAObserver num2 = new NBAObserver("B", lady);
 11 
 12             //lady没来的及通知两位同事
 13             lady.Detach(num1);
 14             lady.Detach(num2);
 15 
 16             //现在的通知者就变成了boss
 17             boss.Attach(num1);
 18             boss.Attach(num2);
 19 
 20             //num2没有看见boss回来,所以boss没来的及通知他
 21             boss.Detach(num2);
 22 
 23             boss.SecretAction = "boss is back";
 24             boss.Notify();
 25 
 26             Console.Read();
 27         }
 28     }
 29 
 30     /// <summary>
 31     /// 通知者的接口
 32     /// 不能用抽象类
 33     /// </summary>
 34     interface Subject
 35     {
 36         void Attach(Observers ob);
 37         void Detach(Observers ob);
 38         void Notify();
 39         string SecretAction
 40         {
 41             get;set;
 42         }
 43     }
 44 
 45     class Boss : Subject
 46     {
 47         IList<Observers> observers = new List<Observers>();
 48         private string action;
 49 
 50         public string SecretAction
 51         {
 52             get
 53             {
 54                 return action;
 55             }
 56 
 57             set
 58             {
 59                 action = value;
 60             }
 61         }
 62 
 63         //增加需要联系的人员
 64         public void Attach(Observers ob)
 65         {
 66             observers.Add(ob);
 67         }
 68 
 69         //减少需要联系的人员
 70         public void Detach(Observers ob)
 71         {
 72             observers.Remove(ob);
 73         }
 74 
 75         //大家看见boss回来后,同事赶紧自行更改工作状态
 76         public void Notify()
 77         {
 78             foreach (Observers o in observers)
 79                 o.Update();
 80         }
 81     }
 82 
 83     /// <summary>
 84     /// 小秘:继承于接口
 85     /// 1.记下需要联系的同事们List<StockObserver>
 86     /// 2.增加需要联系的人员
 87     /// 3.减少联系人员(有可能没有通知到,有可能人员辞职等)
 88     /// 4.秘密通知同事,老板回来了
 89     /// </summary>
 90     class Secretary:Subject
 91     {
 92         IList<Observers> observers = new List<Observers>();
 93         private string action;
 94         
 95         public string SecretAction
 96         {
 97             get
 98             {
 99                 return action;
100             }
101 
102             set
103             {
104                 action = value;
105             }
106         }
107 
108         //增加需要联系的人员
109         public void Attach(Observers ob)
110         {
111             observers.Add(ob);
112         }
113 
114         //减少需要联系的人员
115         public void Detach(Observers ob)
116         {
117             observers.Remove(ob);
118         }
119 
120         //小秘通知了同事后,同事赶紧自行更改工作状态
121         public void Notify()
122         {
123             foreach (Observers o in observers)
124                 o.Update();
125         }
126     }
127 
128     /// <summary>
129     /// 观察者类
130     /// 抽象类
131     /// 偷偷玩的同事的状态都不同,他们的共同点就是1.与小秘联系,2.更新工作状态
132     /// 不同点在于更新状态前不同,所以更新工作状态设置为抽象方法即可
133     /// </summary>
134     abstract class Observers
135     {
136         protected string name;
137         protected Secretary sec;
138 
139         public Observers(string name, Secretary sec)
140         {
141             this.name = name;
142             this.sec = sec;
143         }
144 
145         public abstract void Update();
146     }
147 
148 
149     /// <summary>
150     /// 看股票的同事
151     /// 继承于观察者类
152     /// 根据小秘的偷偷通知修改自己的工作状态
153     /// </summary>
154     class StockObserver : Observers
155     {
156         public StockObserver(string name, Secretary sec)
157             : base(name, sec)
158         {
159         }
160 
161         public override void Update()
162         {
163             Console.WriteLine("{0} {1} 关闭股票行情,继续工作!", sec.SecretAction, name);
164         }
165     }
166 
167     /// <summary>
168     /// 看NBA节目的同事
169     /// 继承于观察者类
170     /// 根据小秘的偷偷通知修改自己的工作状态
171     /// </summary>
172     class NBAObserver : Observers
173     {
174         public NBAObserver(string name, Secretary sec)
175             : base(name, sec)
176         {
177         }
178 
179         public override void Update()
180         {
181             Console.WriteLine("{0} {1} 关闭NBA直播,继续工作!", sec.SecretAction, name);
182         }
183     }
View Code

 

 

 

附:

实现:

  1     class Program
  2     {
  3         static void Main(string[] args)
  4         {
  5             Boss boss = new Boss();
  6             Secretary lady = new Secretary();
  7 
  8             StockObserver num1 = new StockObserver("A", boss);
  9             NBAObserver num2 = new NBAObserver("B", boss);
 10             
 11             //将“看股票”的“关闭股票程序”方法和“看NBA者”的“关闭NBA直播”的方法
 12             //挂钩到老板的“更新”上,也就是将两种不同类的不同方法委托给老板类的更新了。
 13             boss.Update += new EventHandler(num1.CloseStockMarket);
 14             boss.Update += new EventHandler(num2.CloseNBADirectSeeding);
 15 
 16             boss.SecretAction = "boss is back";
 17             boss.Notify();
 18 
 19             Console.Read();
 20         }
 21     }
 22 
 23     /// <summary>
 24     /// 通知者的接口
 25     /// 不能用抽象类
 26     /// 现在抽象通知者由于不下网依赖抽象观察者,所以“增加”和“减少”的方法就没有必要了
 27     /// </summary>
 28     interface Subject
 29     {
 30         void Notify();
 31         string SecretAction
 32         {
 33             get; set;
 34         }
 35     }
 36 
 37     /// <summary>
 38     /// 委托就是一种引用方法的类型。
 39     /// 一旦为委托分配了方法,委托将于该方法具有完全相同的行为
 40     /// 委托方法的使用可以像任何其他方法一样,具有参数和返回值。
 41     /// 委托可以看做是对函数的抽象,是函数的‘类’,委托的实例将代表一个具体的函数
 42     /// 
 43     /// 一个委托可以搭载多个方法,所有的方法被依次唤起
 44     /// 最重要的是,它可以使得委托对象所搭载的方法并不需要属于同一个类
 45     /// 
 46     /// 委托对象所搭载的所有方法必须具有相同的原型和形式,也就是有相同的参数列表和返回值类型
 47     /// </summary>
 48     delegate void EventHandler();   //委托
 49 
 50     class Boss : Subject
 51     {
 52         public event EventHandler Update;
 53 
 54         private string action;
 55 
 56         public string SecretAction
 57         {
 58             get
 59             {
 60                 return action;
 61             }
 62 
 63             set
 64             {
 65                 action = value;
 66             }
 67         }
 68 
 69         //大家看见boss回来后,同事赶紧自行更改工作状态
 70         public void Notify()
 71         {
 72             Update();
 73         }
 74     }
 75 
 76     /// <summary>
 77     /// 小秘:继承于接口
 78     /// 1.记下需要联系的同事们List<StockObserver>
 79     /// 2.增加需要联系的人员
 80     /// 3.减少联系人员(有可能没有通知到,有可能人员辞职等)
 81     /// 4.秘密通知同事,老板回来了
 82     /// </summary>
 83     class Secretary : Subject
 84     {
 85         public event EventHandler Update;
 86 
 87         private string action;
 88 
 89         public string SecretAction
 90         {
 91             get
 92             {
 93                 return action;
 94             }
 95 
 96             set
 97             {
 98                 action = value;
 99             }
100         }
101         
102 
103         //小秘通知了同事后,同事赶紧自行更改工作状态
104         public void Notify()
105         {
106             Update();
107         }
108     }
109     
110     /// <summary>
111     /// 看股票的同事
112     /// 根据小秘的偷偷通知修改自己的工作状态
113     /// </summary>
114     class StockObserver 
115     {
116         private string name;
117         private Subject sub;
118 
119         public StockObserver(string name,Subject sub)
120         {
121             this.name = name;
122             this.sub = sub;
123         }
124 
125         public  void CloseStockMarket()
126         {
127             Console.WriteLine("{0} {1} 关闭股票行情,继续工作!", sub.SecretAction, name);
128         }
129     }
130 
131     /// <summary>
132     /// 看NBA节目的同事
133     /// 根据小秘的偷偷通知修改自己的工作状态
134     /// </summary>
135     class NBAObserver 
136     {
137         private string name;
138         private Subject sub;
139 
140         public NBAObserver(string name,Subject sub)
141         {
142             this.name = name;
143             this.sub = sub;
144         }
145 
146         public void CloseNBADirectSeeding()
147         {
148             Console.WriteLine("{0} {1} 关闭NBA直播,继续工作!", sub.SecretAction, name);
149         }
150     }
View Code

 

 

 

 总结:

观察者模式:定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使他们能够自动更新自己。

  观察者模式所做的工作其实就是在接触耦合。让耦合的双方依赖于抽象,而不是依赖于具体。从而使得各自的变化都不会影响另一边的变化。

 

 委托:就是一种引用方法的类型。一旦为委托分配了方法,委托将与该方法具有完全相同的行为。委托方法的使用可以像其他任何方法一样,具有参数和返回值。委托可以看作是对函数的抽象,是函数的‘类’,委托的实例将代表一个具体的函数。

  一个委托可以搭载多个方法,所有方法被依次唤起。

  委托对象所搭载的方法并不需要属于同一个类。

 

 

 

注:文中所有代码及知识点均来自于《大话设计模式》,本人属于边学边看边敲代码边总结的阶段。

posted @ 2017-10-25 13:41  多多陪着小五  阅读(819)  评论(0编辑  收藏  举报