抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

类之间的关系大体上存在五种—继承(实现)、依赖、关联、聚合、组合。

继承

继承是一种“is-a”关系。多了就不说了,都懂得。

依赖

依赖简单的理解,就是一个类A中的方法使用到了另一个类B。

这种使用关系是具有偶然性的、临时性的、非常弱的,但是B类的变化会影响到A。

比如说,我用笔写字,首先需要一个类来代表我自己,然后需要一个类来代表一支笔,最后,‘我’要调用‘笔’里的方法来写字,用代码实现一下:

1
2
3
4
5
6
7
8
9
10
11
public class Pen {
public void write(){
System.out.println("use pen to write");
}
}

public class Me {
public void write(Pen pen){//这里,pen作为Me类方法的参数。 Me类依赖Pen类
pen.write();
}
}

看到这大家都懂了,因为这种代码你每天都会写。现在你知道了,这就是一种类与类之间的关系,叫做依赖。

这种关系是一种很弱的关系,但是pen类的改变,有可能会影响到Me类的结果,比如我把pen类write方法的方法体改了,me中再调用就会得到不同的结果。

一般而言,依赖关系在Java中体现为局域变量、方法的形参,或者对静态方法的调用。

关联

关联体现的是两个类、或者类与接口之间语义级别的一种强依赖关系。

这种关系比依赖更强、不存在依赖关系的偶然性、关系也不是临时性的,一般是长期性的,而且双方的关系一般是平等的、关联可以是单向、双向的。

1
2
3
4
5
6
7
8
9
10
11
12
// pen 还是上面的pen
public class You {
private Pen pen; // 让pen成为you的类属性

public You(Pen p){
this.pen = p;
}

public void write(){
pen.write();
}
}

被关联类B以类属性的形式出现在关联类A中,或者关联类A引用了一个类型为被关联类B的全局变量的这种关系,就叫关联关系。

在Java中,关联关系一般使用成员变量来实现。

聚合

聚合是关联关系的一种特例,他体现的是整体与部分、拥有的关系,即has-a的关系

看下面一段代码:

1
2
3
4
5
public class Family {
private List<Child> children; //一个家庭里有许多孩子

// ...
}

在代码层面,聚合和关联关系是一致的,只能从语义级别来区分。普通的关联关系中,a类和b类没有必然的联系,而聚合中,需要b类是a类的一部分,是一种”has-a“的关系,即 a has-a b; 比如家庭有孩子,屋子里有空调。

但是,has 不是 must has,a可以有b,也可以没有。a是整体,b是部分,整体与部分之间是可分离的,他们可以具有各自的生命周期,部分可以属于多个整体对象,也可以为多个整体对象共享。

不同于关联关系的平等地位,聚合关系中两个类的地位是不平等。

组合

组合也是关联关系的一种特例,他体现的是一种contains-a的关系,这种关系比聚合更强,也称为强聚合。

1
2
3
4
5
6
public class Person {
private Eye eye = new Eye(); //一个人有鼻子有眼睛
private Nose nose = new Nose();

// ....
}

组合同样体现整体与部分间的关系,但此时整体与部分是不可分的,整体的生命周期结束也就意味着部分的生命周期结束。

就像你有鼻子有眼睛,如果你一不小心结束了生命周期,鼻子和眼睛的生命周期也会结束,而且,鼻子和眼睛不能脱离你单独存在。

只看代码,你是无法区分关联,聚合和组合的,具体是哪一种关系,只能从语义级别来区分。

同样,组合关系中,两个类关系也是不平等的。

组合,聚合和继承

依赖关系是每一个java程序都离不开的,所以就不单独讨论了,普通的关联关系也没有什么特殊的地方,下面我们重点研究一下组合,聚合和继承。

聚合与组合

聚合与组合都是一种关联关系,只是额外具有整体-部分的意义。

部件的生命周期不同

聚合关系中,整件不会拥有部件的生命周期,所以整件删除时,部件不会被删除。再者,多个整件可以共享同一个部件。

组合关系中,整件拥有部件的生命周期,所以整件删除时,部件一定会跟着删除。而且,多个整件不可以同时间共享同一个部件。

这个区别可以用来区分某个关联关系到底是组合还是聚合。两个类生命周期不同步,则是聚合关系,生命周期同步就是组合关系。

聚合关系是【has-a】关系,组合关系是【contains-a】关系

平时我们只讨论组合和继承的时候,认为组合是【has-a 】关系,而事实上,聚合才是真正的【has-a】关系,组合是更深层次的【contains-a】关系。

由于【contains-a】关系是一种更深的【has-a】关系,所以说组合是【has-a】关系也是正确的。

组合和继承

这个才是本文的重点。

学过设计模式的都知道,要“少用继承,多用组合”,这究竟是为什么呢?

我们先来看一下组合和继承各自的优缺点:

组合

优点:

  • 不破坏封装,整体类与局部类之间松耦合,彼此相对独立
  • 具有较好的可扩展性
  • 支持动态组合。在运行时,整体对象可以选择不同类型的局部对象
  • 整体类可以对局部类进行包装,封装局部类的接口,提供新的接口

缺点:

  • 整体类不能自动获得和局部类同样的接口
  • 创建整体类的对象时,需要创建所有局部类的对象

继承

优点:

  • 子类能自动继承父类的接口
  • 创建子类的对象时,无须创建父类的对象

缺点:

  • 破坏封装,子类与父类之间紧密耦合,子类依赖于父类的实现,子类缺乏独立性
  • 支持扩展,但是往往以增加系统结构的复杂度为代价
  • 不支持动态继承。在运行时,子类无法选择不同的父类
  • 子类不能改变父类的接口

(后面罗里吧嗦的,不记了)

参考来源

https://www.cnblogs.com/ccgjava/p/11433745.html

评论