...待续....
上一篇以完成任务式的方式实现了插排的功能.
其中插头的规范部分值得思考, 上文采用了abstract class的方式,
既然是定义规范, 为什么不用接口方式呢?
一. 下面把上面的例子改造一下, 将原来的abstract class改为接口.
1 public interface igbelectricalappliance 2 { 3 void input(int left, int right); 4 } 5 6 public class output 7 { 8 public output() 9 { 10 this.eacollection = new list<igbelectricalappliance>(); 11 } 12 private list<igbelectricalappliance> eacollection; 13 public void powered(int left,int right) 14 { 15 foreach (var item in eacollection) 16 { 17 item.input(left,right); 18 } 19 } 20 public void addinput(igbelectricalappliance item) 21 { 22 eacollection.add(item); 23 } 24 25 public void removeinput(igbelectricalappliance item) 26 { 27 eacollection.remove(item); 28 } 29 } 30 31 32 33 public class tv : igbelectricalappliance 34 { 35 public void input(int left, int right) 36 { 37 show(); 38 sound(); 39 } 40 41 private void show() 42 { 43 console.writeline("i am showing"); 44 } 45 private void sound() 46 { 47 console.writeline("i am sounding"); 48 } 49 } 50 51 public class electrickettle : igbelectricalappliance 52 { 53 public void input(int left, int right) 54 { 55 heat(); 56 } 57 58 private void heat() 59 { 60 console.writeline("i am heating"); 61 } 62 }
运行一下结果也是一样, 看起来也没啥不同的.
那么到底该用那种方法呢?
二. 现在看一下 abstract class和interface的区别
二者都可以定义一些"规范", 都不可以实例化,
但abstract class中可以有实现的方法, 接口不可以
假如电器有一一些共用的方法例如功率计算(powercalculation)等, 可以在abstract class中实现, 非常方便, 这是interface无法实现的, 如下面代码所示
1 public abstract class gbelectricalappliance 2 { 3 public abstract void input(int left, int right); 4 5 /// <summary> 6 /// 计算实时功率 7 /// </summary> 8 /// <param name="u">电压</param> 9 /// <param name="i">电流</param> 10 public void powercalculation(int u ,int i) 11 { 12 console.writeline("power:" + (u * i).tostring()); 13 } 14 15 //其他通用方法 16 }
从另一个不同来看, interface允许继承多个, 而abstract class不可以.
所以我们也可以这样想, abstract class的含义是"是xx", 反映到例子总就是插座要求插上的设备是国标电器.
如果我们把接口再改一下,
1 public interface igbelectricalable 2 { 3 void input(int left, int right); 4 } 5 6 public class other : igbelectricalable 7 { 8 public void input(int left, int right) 9 { 10 dosomething(); 11 } 12 13 private void dosomething() 14 { 15 console.writeline("i am other"); 16 } 17 }
只是改了个名字, 大概意思是拥有符合国标标准插头的, 注意这里不再强调是电器了.
例如某些大型机械(上面代码中的other), 用电部分可能只是辅助, 再定义为电器已经有点不合适了, 它也不需要继承 gbelectricalappliance.
三.原来的代码调整如下
1 public class output 2 { 3 public output() 4 { 5 this.eacollection = new list<igbelectricalable>(); 6 } 7 private list<igbelectricalable> eacollection; 8 public void powered(int left,int right) 9 { 10 foreach (var item in eacollection) 11 { 12 item.input(left,right); 13 } 14 } 15 public void addinput(igbelectricalable item) 16 { 17 eacollection.add(item); 18 } 19 20 public void removeinput(igbelectricalable item) 21 { 22 eacollection.remove(item); 23 } 24 } 25 26 public abstract class gbelectricalappliance:igbelectricalable 27 { 28 public abstract void input(int left, int right); 29 30 /// <summary> 31 /// 计算实时功率 32 /// </summary> 33 /// <param name="u">电压</param> 34 /// <param name="i">电流</param> 35 public void powercalculation(int u, int i) 36 { 37 console.writeline("power:" + (u * i).tostring()); 38 } 39 40 //其他通用方法 41 } 42 43 public class tv : gbelectricalappliance 44 { 45 public override void input(int left, int right) 46 { 47 show(); 48 sound(); 49 } 50 51 private void show() 52 { 53 console.writeline("i am showing"); 54 } 55 private void sound() 56 { 57 console.writeline("i am sounding"); 58 } 59 } 60 61 public class electrickettle : gbelectricalappliance 62 { 63 public override void input(int left, int right) 64 { 65 heat(); 66 } 67 68 private void heat() 69 { 70 console.writeline("i am heating"); 71 } 72 }
原来的tv和kettle依然可以继承自 gbelectricalappliance, 这样它们的共用方法 powercalculation依然生效,
而gbelectricalappliance继承了接口 igbelectricalable
测试一下将other也插入插排
1 class program 2 { 3 static void main(string[] args) 4 { 5 output op = new output(); 6 op.addinput(new tv()); 7 op.addinput(new electrickettle()); 8 op.addinput(new other()); 9 10 op.powered(220, 0); 11 } 12 }
可以看到结果中出现了 "i am other".
四:小结
本次用接口的方式对原例子进行了改造, 进一步将插排和插入设备解耦.
文一中, 插排要求插入的设备是符合国标的电器.
本文中, 插排要求插入的设备有符合国标的插头即可, 无论什么样的设备, 无论其是否是电器.
五.思考
由此, 现在进一步想一想, 既然是有符合国标的插头即可.而插头无非就是input一个方法.
而前两种方式无论是抽象类还是接口, 都是将设备本身放入了插排的集合中,
即 addinput(igbelectricalable item), 然后再由插排调用集合中设备的input方法.
这貌似搞得有点复杂, 耦合度还是高, 而且也不符合实际中直插入插头而不是整个设备的事实.
那么我们是否可以将此处的参数用由插入设备本身(观察者)改为设备的input方法呢
即 addinput(input _input), 然后再由插排直接调用集合中的input方法.
下篇继续讨论..