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

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

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


结尾处有这样的问题:


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


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

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 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; 测试了一下 , 已经编译不通过了.


四. 小结

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



目录
相关文章
|
7月前
|
C# Windows
C#OOP之十一 委托和事件
C#OOP之十一 委托和事件
36 0
C#编程:如何理解委托-2
C#编程:如何理解委托-2
C#编程:如何理解委托
C#编程:如何理解委托
155 0
|
C# 图形学
Unity 3D观察者设计模式-C#委托和事件的运用
C#观察者设计模式 本文提供全流程,中文翻译。 Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 —— 高分辨率用户请根据需求调整网页缩放比例) Chinar —— 心分享、心...
1786 0