zoukankan      html  css  js  c++  java
  • 一个插排引发的设计思想 (二) 抽象类与接口

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

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

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

    ...待续....

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

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

    下篇继续讨论..

  • 相关阅读:
    模块安装
    yagmail 邮件模块
    unittest 单元测试
    用 yaml 写测试用例
    nnlog 日志模块
    Jenkins安装以及邮件配置
    数据驱动之 python + requests + Excel
    url 编码解码
    15. 测试环境部署-linux
    vue使用UEditor富文本编辑器
  • 原文地址:https://www.cnblogs.com/FlyLolo/p/8386191.html
Copyright © 2011-2022 走看看