一个插排引发的设计思想 (三) 委托与事件

 

一个插排引发的设计思想 (一) 观察者模式

一个插排引发的设计思想 (二) 抽象类与接口

一个插排引发的设计思想 (三) 委托与事件

...待续....

 

前两篇文章循序渐进的介绍了观察者模式、抽象类和接口, 并分析了抽象类和接口的不同.

结尾处有这样的问题:

无论是抽象类还是接口, 都是将设备本身放入了插排的集合中, 那么我们是否可以将此处的参数改为设备的Input方法呢?

那么我们就用到了委托Delegate.

1    public delegate void InputDelegate(int left, int right);

看到接下来的代码, 老鸟别笑, 请允许我"循序渐进"的引导着思路重构.

我们用委托InputDelegate定义了插头的标准. 那么原来的代码改变一下

一. 用方法作为参数传递, 代替原来的整个设备

 1     public delegate void InputDelegate(int left, int right);
 2     public class OutPut
 3     {
 4         public OutPut()
 5         {
 6             this.EACollection = new List<InputDelegate>();
 7         }
 8         private List<InputDelegate> EACollection;
 9         public void powered(int left, int right)
10         {
11             foreach (var item in EACollection)
12             {
13                 item(left, right);
14             }
15         }
16         public void AddInput(InputDelegate item)
17         {
18             EACollection.Add(item);
19         }
20 
21         public void RemoveInput(InputDelegate item)
22         {
23             EACollection.Remove(item);
24         }
25     }
26 
27     class Program
28     {
29         static void Main(string[] args)
30         {
31             OutPut op = new OutPut();
32             op.AddInput(new TV().Input);
33             op.AddInput(new ElectricKettle().InputAAAA);
34 
35             op.powered(220, 0);
36 
37             Console.ReadKey();
38         }
39     }

原来的TV和ElectricKettle无需任何继承任何抽象类和接口, 只要有和定义的Delegate一样的方法签名的方法即可.

甚至名字都可以不一样, 例如ElectricKettle的input方法我随便改了一下改成了InputAAAA依然没问题.

 1     public class ElectricKettle
 2     {
 3         public void InputAAAA(int left, int right)
 4         {
 5             Heat();
 6         }
 7 
 8         private void Heat()
 9         {
10             Console.WriteLine("I am heating");
11         }
12     }

通过上面的方法, 我们把插入插排的参数由整个设备改成了设备的插头. 

功能是实现了, 但Delegate用起来没必要那么麻烦, 我们继续改

二. 用+=和-=来操作

我们改造一下Output类

 1     public delegate void InputDelegate(int left, int right);
 2     public class OutPut
 3     {
 4         public InputDelegate inputDelegate;
 5         public void powered(int left, int right)
 6         {
 7             inputDelegate(left, right);
 8         }
 9     }
10 
11     class Program
12     {
13         static void Main(string[] args)
14         {
15             OutPut op = new OutPut();
16             op.inputDelegate += new TV().Input;
17             op.inputDelegate += new ElectricKettle().InputAAAA;
18 
19             op.powered(220, 0);
20 
21             Console.ReadKey();
22         }
23     }

简洁多了, 根据Delegate的特性, 插排集本身也被inputDelegate代替了.

在调用的时候, 我们只需将input方法 +=到该inputDelegate即可.

三. 委托和事件

上面的例子貌似已经很好了, 但既然是插排, 也就是可能会有好多插头来插拔, 而插头之间互不干涉, 调用的位置可能存在于系统的任何位置 .

但上面的代码让我们想到一个问题,

我们把"集和"暴露出来了, 之前的 private List<IGBElectricalable> EACollection是私有的, 只可以通过add和 remove两个方法操作.

现在我们把它public了,  哪个捣蛋的写了一句op.inputDelegate = null,  把插排都弄没了, 让别的插头怎么办.

所以我们还希望像原来那样只提供增减的方法, 不允许赋值, 这里我们就用到了事件.

 1     public delegate void InputDelegate(int left, int right);
 2     
 3     public class OutPut
 4     {
 5         public event InputDelegate inputEvent;
 6         public void powered(int left, int right)
 7         {
 8             inputEvent(left, right);
 9         }
10     }
11 
12     class Program
13     {
14         static void Main(string[] args)
15         {
16             OutPut op = new OutPut();
17             
18             op.inputEvent += new TV().Input;
19             op.inputEvent += new ElectricKettle().InputAAAA;
20             //op.inputEvent = null;
21             op.powered(220, 0);
22 
23             Console.ReadKey();
24         }
25     }

Output中的 inputDelegate 改为了 inputEvent, inputEvent不再允许通过=来赋值了.

main方法中注释的一行 //op.inputEvent = null; 测试了一下 , 已经编译不通过了.

四. 小结

本文通过委托, 将方法作为参数注册到了插排中.  因为安全问题, 又将委托改为了事件.

 

posted @ 2018-02-01 09:19  FlyLolo  阅读(951)  评论(0编辑  收藏  举报