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

上一篇以完成任务式的方式实现了插排的功能.

其中插头的规范部分值得思考, 上文采用了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方法.

下篇继续讨论..

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏walterlv - 吕毅的博客

C#/.NET 匿名函数会捕获变量,并延长对象的生命周期

发布于 2018-01-05 01:26 更新于 2018-09...

10010
来自专栏大前端开发

【趣解编程】变量

如果把编程比作做菜的话,变量就是那些碗盆瓢勺,或装着原材料,或在做菜的过程中临时的摆放半成品,或装着最后的成品菜。

10440
来自专栏梧雨北辰的开发录

Python学习(3):理解计算机中编码三、认识常见的计算机编码

17930
来自专栏Core Net

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

29960
来自专栏码洞

老板们都应该学一学 Redis,它能管理上亿对象,你们呢?

我们知道一个大型的公司往往都具有复杂的组织结构,成百上千号员工,要做到大而不乱,就必须依靠合理的组织结构来优化内部的交流成本。Redis 内部也有组织结构,不同...

18550
来自专栏菩提树下的杨过

linq to sql生成not in语句的小技巧

以前一直觉得linq to sql生成类似where id not in (1,3,5)或where id not in (select id from ......

20150
来自专栏数据结构与算法

HDU 1848 Fibonacci again and again(SG函数)

Problem Description 任何一个大学生对菲波那契数列(Fibonacci numbers)应该都不会陌生,它是这样定义的: F(1)=1; ...

35460
来自专栏技术博客

编写高质量代码改善C#程序的157个建议[C#闭包的陷阱、委托、事件、事件模型]

本文已更新至http://www.cnblogs.com/aehyok/p/3624579.html 。本文主要学习记录以下内容:

10730
来自专栏菩提树下的杨过

利用Reflector把"闭包"看清楚

今天老赵在园子里发了一篇文章"警惕匿名方法造成的变量共享",立即引起了大家的广泛关注(老赵就是园子的"人气天王",呵呵),而且这个问题园子里也有其它几篇文章做了...

20750
来自专栏前端黑板报

译《ES6的6个小特性》

Six Tiny But Awesome ES6 Features.md JS社区的每个人都喜欢新的API、语法以及一些简单、明了更高效的完成重要任务的新特性...

19950

扫码关注云+社区

领取腾讯云代金券