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方法.

    下篇继续讨论..

  • 相关阅读:
    jquery实现选项卡(两句即可实现)
    常用特效积累
    jquery学习笔记
    idong常用js总结
    织梦添加幻灯片的方法
    LeetCode "Copy List with Random Pointer"
    LeetCode "Remove Nth Node From End of List"
    LeetCode "Sqrt(x)"
    LeetCode "Construct Binary Tree from Inorder and Postorder Traversal"
    LeetCode "Construct Binary Tree from Preorder and Inorder Traversal"
  • 原文地址:https://www.cnblogs.com/FlyLolo/p/8386191.html
Copyright © 2011-2022 走看看