`
aladdin_leon
  • 浏览: 118857 次
  • 性别: Icon_minigender_1
  • 来自: 哈尔滨
社区版块
存档分类
最新评论

继承还是关联?是个问题

阅读更多

     当我们的讲面向对象或系统设计的老师又在课堂上向我们传授在进行复用时“尽量使用合成/聚合,而不是使用继承”的“定理”的时候,可能我们仿佛真的找到了问题的解决方法,但是这背后意味着什么呢?我们为什么需要这样做呢?是否这是问题的最佳解决方案了呢?这一切的问题起源于一个名为“合成聚合复用原则”的OOD原则...
     下面还是通过CSDN上Health King的专栏的一篇文章来进行讲述吧!涂了颜色[ ]的是我自己做得注释。
     合成(Composition)和聚合(Aggregation)都是关联(Association)的特殊种类。聚合表示整体和部分的关系,表示“拥有”;合成则是一种更强的“拥有”,部分和整体的生命周期一样。合成的新的对象完全支配其组成部分,包括它们的创建和湮灭等。一个合成关系的成分对象是不能与另一个合成关系共享的。
     换句话说,合成是值的聚合(Aggregation by Value),而一般说的聚合是引用的聚合(Aggregation by Reference)。
     [不过好像现在对合成和聚合不是太追究了,特别是在UML2.0里面,所以这个问题我们知道就可以了]
     简短的说,合成-聚合复用原则(CARP)是指:尽量使用合成/聚合,而不是使用继承。 [定理出现了]
     在OOD中,有两种基本的办法可以实现复用,一种是通过合成/聚合,另外一种就是通过继承[当然还有好多扩展型的设计模式可以拿来用,例如最长见的Decorator模式,这都是后话了]。通过合成/聚合的好处是:
     ----- 新对象存取成分对象的唯一方法是通过成分对象的接口。 [恩,符合依赖倒转原则,赞!]
     ----- 这种复用是黑箱复用,因为成分对象的内部细节是新对象所看不见的。 [降低了复用的复杂性]
     ----- 这种复用支持包装。 [不知道是不是在说Decorator模式呢!]
     ----- 这种复用所需的依赖较少。 [想要关联谁,我就关联谁,我的地盘我做主,哈哈]
     ----- 每一个新的类可以将焦点集中在一个任务上。 [可以将一些子任务分派的成分对象里面,而本身只关心自己的任务,这也是设计一个对象所要考虑的,每个对象都有自己的责任,他只需要把自己的责任做好就足够了,不要去干涉其他的对象的责任,看来,我们的系统我们不需要多管闲事的对象]
     ----- 这种复用可以在运行时间内动态进行,新对象可以动态的引用与成分对象类型相同的对象。 [增加了复用的灵活性,对复用可以进行灵活的配置]
     ----- 作为复用手段可以应用到几乎任何环境中去。 [这句话有一些不明白了?]
     它的缺点就是系统中会有较多的对象需要管理。 [还是不能避免好的设计会带来复杂性的问题]
     通过继承来进行复用的优点是:
     -----新的实现较为容易,因为超类的大部分功能可以通过继承的关系自动进入子类。
     ----- 修改和扩展继承而来的实现较为容易。
     通过继承来实现复用的缺点是:
     ----- 继承复用破坏包装,因为继承将超类的实现细节暴露给子类。由于超类的内部细节常常是对于子类透明的,所以这种复用是透明的复用, 又称“白箱”复用。 [但是有时这种透明,会代来不好的结果,可能有的时候我们只想去用一个功能,而并不想弄清楚功能是怎么实现的]
     ----- 如果超类发生改变,那么子类的实现也不得不发生改变。 [又是改变,但谁能避免改变呢,我们能唯一确定不变的就是改变]
     ----- 从超类继承而来的实现是静态的,不可能在运行时间内发生改变,没有足够的灵活性。
     ----- 继承只能在有限的环境中使用。 [如果有一个final类,再有本事,我们也不能继承它,所以只能去用关联了]
     要正确的选择合成/复用和继承,必须透彻的理解里氏代换原则和Coad法则。里氏代换原则前面学习过,Coad法则由Peter Coad提出,总结了一些什么时候使用继承作为复用工具的条件。 [这个原则我认为是最重要的,它给我们面对“继承还是关联”问题时一个更加细致和合理指导,而不是象生搬硬套的定理一样强暴我们的思维]只有当以下的Coad条件全部被满足时,才应当使用继承关系:
     ----- 子类是超类的一个特殊种类,而不是超类的一个角色,也就是区分“Has-A”和“Is-A”。只有“Is-A”关系才符合继承关系,“Has-A”关系应当用聚合来描述。 [这个问题看似简单,但是实际上是很难分辨的,只有慢慢地积累才会变成“火眼金睛”]
     ----- 永远不会出现需要将子类换成另外一个类的子类的情况。如果不能肯定将来是否会变成另外一个子类的话,就不要使用继承。 [就像前面所说的,利用继承进行复用是静态的,所以运行时或者将来的改变是继承的硬伤]
     ----- 子类具有扩展超类的责任,而不是具有置换调(override)或注销掉(Nullify)超类的责任。如果一个子类需要大量的置换掉超类的行为,那么这个类就不应该是这个超类的子类。
     ----- 只有在分类学角度上有意义时,才可以使用继承。不要从工具类继承。 [不要进行没有意义的继承,这一点来说我们还是很容易分辨的,只要你对设计还有那么一点对“优美”的追求,就不会犯这个错误的]
     错误的使用继承而不是合成/聚合的一个常见原因是错误的把“Has-A”当成了“Is-A”。“Is-A”代表一个类是另外一个类的一种;“Has-A”代表一个类是另外一个类的一个角色,而不是另外一个类的特殊种类。 [下面的用例很不错的,我们是不是一直在犯这个错误呢,反正我是一直在犯这个错误,快来看看吧]
     我们看一个例子。如果我们把“人”当成一个类,然后把“雇员”,“经理”,“学生”当成是“人”的子类。这个的错误在于把“角色”的等级结构和“人”的等级结构混淆了。“经理”,“雇员”,“学生”是一个人的角色,一个人可以同时拥有上述角色。如果按继承来设计,那么如果一个人是雇员的话,就不可能是经理,也不可能是学生,这显然不合理。正确的设计是有个抽象类“角色”,“人”可以拥有多个“角色”(聚合),“雇员”,“经理”,“学生”是“角色”的子类。
     另外一个就是只有两个类满足里氏代换原则的时候,才可能是“Is-A”关系。也就是说,如果两个类是“Has-A”关系,但是设计成了继承,那么肯定违反里氏代换原则。 [里氏代换原则马上就会讲了,这几天在忙着面试,时间总是有点不够用...]

     原文链接:http://blog.csdn.net/kxy/archive/2005/07/06/415574.aspx

分享到:
评论
1 楼 cddcdd 2007-08-22  
 

相关推荐

    Hibernate数据关联映射与继承策略

    2. **一对多关联(One-to-Many)**:一个实体可以与数据库表中的多个记录关联。通常使用集合类型(如 List, Set)来存储关联对象,通过在子类的一方定义外键实现。 3. **多对一关联(Many-to-One)**:与一对多相反...

    UML中继承实现依赖关联聚合组合的联系与区别_线条箭头.doc

    UML 中继承、实现、依赖、关联、聚合、组合的联系与区别 UML 中的继承关系是指一个类继承另外一个类的功能,并可以增加它自己的新功能的能力,继承是类与类或者接口与接口之间最常见的关系。在 Java 中此类关系通过...

    UML学习之依赖_关联_聚合_组合_继承

    ### UML学习之依赖、关联、聚合、组合与继承 #### 一、泛化(Generalization) **概念:** 泛化表示的是类与类之间的继承关系、接口与接口之间的继承关系,或者是类对接口的实现关系。在UML中,泛化关系通常用一个带...

    使用jpa映射关联和继承

    本篇文章将深入探讨如何在JPA中映射关联和实现继承。 **一、JPA关联映射** 1. **一对一(OneToOne)映射**:一个实体对象对应数据库中的一个记录。通过`@OneToOne`注解来实现,可以是单向或双向。`@JoinColumn`...

    UML中几种类间关系:继承、实现、依赖、关联、聚合、组合的联系与区别

    在UML中,有六种主要的类间关系:继承、实现、依赖、关联、聚合和组合。理解这些关系对于设计高质量的软件架构至关重要。 1. **继承**: 继承是类与类之间的一种层次结构关系,表示一个类(子类)可以从另一个类...

    CIM模型中多表继承关联的分析解决

    在CIM(Common Information Model)模型中,多表继承关联的分析解决是一个关键的问题,它涉及到数据的存储、查询效率以及系统扩展性。CIM模型是一种标准,用于描述电力系统的各种对象及其相互关系,用于数据交换和...

    几种类间关系:继承、实现、依赖、关联、聚合、组合

    几种类间关系:继承、实现、依赖、关联、聚合、组合。可做为开发设计时速查手册。

    UML 继承,实现,依赖,关联,聚合

    本文将深入探讨UML中的五个关键关系:继承、实现、依赖、关联和聚合,以及它们在软件设计中的作用。 1. **继承(Inheritance)**: 继承是面向对象编程的核心概念之一,它允许一个类(子类或派生类)从另一个类...

    主从表关联问题

    一、使用视图meeting将多表关联整合在一起 二、通过Sql语句筛选数据 三、建立和主从表的关联 四、注意在CrystalReport1表中插入子报表的时候,一定要将主从表的关联字段设置好,否则出乱子

    用java写的左关联右关联join类

    然后,分别为左关联和右关联创建`LeftJoin`和`RightJoin`类,它们都继承自`JoinOperation`。这两个类都需要处理两个输入数据集合,并根据指定的关联条件进行操作。 在`LeftJoin`类中,我们需要遍历左侧集合,对于每...

    JPA视频教程_使用jpa映射关联和继承

    在这个**“JPA视频教程_使用jpa映射关联和继承”**中,我们将深入探讨如何利用JPA来处理实体之间的关联和类的继承关系。 **1. JPA 注解** JPA 注解是实现ORM的主要手段,它们可以直接在实体类上声明,用于定义...

    Hibernate ORM - 继承关联关系之union-subclass

    本文将深入探讨Hibernate ORM中的一个特定概念——继承关联关系的“union-subclass”策略。这个策略涉及到如何在面向对象的设计中处理类的继承关系,并将其映射到数据库中。 首先,我们来理解继承关联关系。在面向...

    UML类图关系泛化、继承、实现、依赖、关联、聚合、组合.doc

    UML类图关系泛化、继承、实现、依赖、关联、聚合、组合 UML类图关系是Unified Modeling Language(统一建模语言)的核心概念之一,用于描述系统中的对象之间的关系。本文将对UML类图关系中的泛化、继承、实现、依赖...

    用Hibernate映射继承关系

    除了继承关系,描述中还提到了Hibernate的关联映射,这是另一个核心概念: - **一对一(One-to-One)映射**:一个实体与另一个实体有唯一的关系,例如一个人只有一个身份证。可以使用`@OneToOne`注解实现,可以是...

    Java继承习题

    - Java不支持多重继承,即一个子类只能有一个直接父类。因此,错误的说法是 **A. 一个子类可有多个父类**。 10. **访问权限** - **题目**: 关于继承下面说法正确的是 - A. 子类能够继承父类私有的属性; - B. ...

    hibernate关联映射实例

    在现实世界中,一个实体可能会与多个其他实体相关联,比如一个用户可以有多个订单。在Hibernate中,我们通过`@OneToMany`注解来实现这种关系。这个注解通常放在拥有众多子项的一方,配置`mappedBy`属性来指定子项在...

    java基础学习(继承与接口的区别及产生原因)

    例如,在上面提到的例子中,如果D类同时继承B类和C类,而B类和C类又都继承自A类,那么D类在调用A类的方法时,就会出现不确定应该从哪个路径(B还是C)调用的问题。 ### Java中的接口 为了解决多继承的问题,Java...

    继承映射的

    在具体的应用场景下,如“extendMapping”工程中,继承映射被广泛应用于解决复杂的实体间关系问题。通过精心设计的继承映射策略,可以将继承关系树中的每个类对应到数据库的一个表,从而有效管理不同级别的实体属性...

    Mybatis表对象继承实现

    而在数据库设计中,表继承是指将具有继承关系的对象存储在多个相关联的表中,这些表之间以特定的方式相互关联。 在数据库表对象继承的三种实现方式中: 1. 第一种方式是所有对象的属性都存放在一张大表中,并通过...

    MFC(C++)程序与文件关联(后缀名)含CRegRelateExt 代码

    这个类继承自 `CRegKey`,这是一个来自MFC的类,用于处理Windows注册表的操作。 ##### 3.1 类的定义 ```cpp class CRegRelateExt : public CRegKey { // ... }; ``` `CRegRelateExt` 类的主要功能包括: - **...

Global site tag (gtag.js) - Google Analytics