...待续....
前两篇文章循序渐进的介绍了观察者模式、抽象类和接口, 并分析了抽象类和接口的不同.
结尾处有这样的问题:
无论是抽象类还是接口, 都是将设备本身放入了插排的集合中, 那么我们是否可以将此处的参数改为设备的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; 测试了一下 , 已经编译不通过了.
四. 小结
本文通过委托, 将方法作为参数注册到了插排中. 因为安全问题, 又将委托改为了事件.