• OOD沉思录 --- 类和对象的关系 --- 包含关系2


    4.6 尽量让类中定义的每个方法尽可能多地使用包含的对象(即数据成员)

    这其实就是高内聚的翻版强调。如果每个类的情况并非如此,那很可能是这一个类表示了两个或更多的概念,记住一个类只应该表示一个概念。    

    最明显的情况就是类的一半方法使用了一半的数据成员,而另一半方法使用了另一半的数据成员,那么这个类就应该一分为二。    

    我们假设一个澡堂,有VIP客户和普通客户,各自有不同的服务(普通客户享受中专生服务,VIP客户享受大学生服务),则定义如下:

    1. class 澡堂  
    2. {  
    3.      stack<中专生> 普通服务员;  
    4.      stack<大学生> VIP服务员;  
    5.        
    6.      普通接待()  
    7.      {  
    8.           普通服务员.Pop().侍候();                 
    9.      }  
    10.      普通结帐()  
    11.      {  
    12.           普通服务员.Pop().结帐();  
    13.      }  
    14.   
    15.      Vip接待()  
    16.      {  
    17.           VIP服务员.Pop().侍候();  
    18.      }  
    19.      VIP结帐()  
    20.      {  
    21.           VIP服务员.Pop().结帐();  
    22.      }  
    23. }  
    这是一个我经常看到的类似结构,这种结构不可避免地会在使用者的代码里进行很多条件判断,来确定到底调用那个版本的方法,而这种判断最好避免。     
    原因在于这一个类包含了两个概念,一个是针对普通客户,一个是针对VIP客户,违反了本条原则,我们应当将其分开,这里可以考虑再次抽象
    1. class 澡堂  
    2. {          
    3.     abstract 接待();  
    4.     abstract 结帐();  
    5. }  
    6. class 普通澡堂:澡堂  
    7. {  
    8.      stack<中专生> 服务员;           
    9.      接待()  
    10.      {  
    11.           服务员.Pop().侍候();                 
    12.      }  
    13.      结帐()  
    14.      {  
    15.           服务员.Pop().结帐();  
    16.      }  
    17. }  
    18. class VIP澡堂:澡堂  
    19. {  
    20.      stack<大学生> 服务员;  
    21.   
    22.      Vip接待()  
    23.      {  
    24.           服务员.Pop().侍候();  
    25.      }  
    26.      VIP结帐()  
    27.      {  
    28.           服务员.Pop().结帐();  
    29.      }  
    30. }  

        这样这个类的使用者可以使用如下方法:

    1. 澡堂 tmp=null;  
    2. if(顾客 is 普通客户)  
    3.      tmp=new 普通澡堂();         
    4. if(顾客 is VIP客户)  
    5.      tmp=new VIP澡堂();  
    6. tmp.接待();  
    7. //......  
    8. tmp.结帐();  

        眼神好的可能马上就会提出,这里也进行了判断,但是这里的判断我们可以通过两种手段来处理    

    一,字典        

    在外部保存一个字典:Dictionary<顾客类型,澡堂> dic;         那么上面的代码就成为下面这样:

    1. 澡堂 tmp=dic[顾客类型];  
    2. tmp.接待();  
    3. //......  
    4. tmp.结帐();  

    二,简单工厂        

    实现一个简单工厂,澡堂Factory,则使用代码如下:

    1. 澡堂 tmp=澡堂Factory.Create(顾客类型);  
    2. tmp.接待();  
    3. //......  
    4. tmp.结帐();  

         这两种方式都可以在程序配置的时候进行调整,将类型的依赖延迟到配置细节中(而这正是类型注入的要旨,别被那些专有的很玄的框架名次忽悠,其实就是这么简单)。

  • 相关阅读:
    07: mysql锁和事物隔离
    06: mysql索引查找原理及调优
    06: 字典、顺序表、列表、hash树 实现原理
    05:树结构
    02:MongoDB操作
    01:MongoDB基础
    02: CMDB设计思路
    二级制包安装Tomcat 与 RPM包安装Tomcat
    Docker的volume机制实现容器数据的持久性存储
    配置docker的私有仓库
  • 原文地址:https://www.cnblogs.com/stst/p/4909640.html
Copyright © 2020-2023  润新知