类之间的关系-更合理的架构

类之间的关系

最常见的类之间的关系:
- 继承(is a)
- 聚合(has a)
- 依赖(uses a)


继承 is a

继承不仅继承了父类的属性和方法,还继承了种类,与父类形成“是一种”的关系,即“is a”的关系。
所有的子类“是一种”父类。喜鹊“是一种”鸟,麻雀也“是一种”鸟。

聚合 has a

聚合较好理解,一个对象包含另一个对象,如:手机类聚合相机类,很合理的,手机一般内置了拍照功能,手机对象自然而然包含相机对象。
显然,这里手机是“有一个”相机(功能),而不是“是一种”相机了。
注:聚合通常也会被称为关联or复合

依赖 uses a

依赖最好理解。类A的一个方法必须依赖另一个类的对象才能实现想要的效果。
和聚合比较,细节至代码级的差别一般表现为:
聚合是类A将类B聚合为自己的一个属性,所有类A的所有对象天生拥有类B对象;
依赖是类A的方法操作类B的对象,要想完成实现这个方法,要用到类B对象。


常用类关系的UML符号

常见类关系UML符号


更合理的架构

避免滥用继承,思考类的关系是“是一种”or“有一个”,优先考虑利用聚合关系(“有一个”),适当的时候再用上继承,是设计更有弹性。


举个栗子

有三个类:
- 相机类:Camera.java
- 手机类:Phone.java
- 音乐手机类:MusicPhone.java

其中,手机肯定是内置相机功能的,所以手机“有一种”相机;而音乐手机肯定“是一种”手机。类之间聚合和继承的关系这样较为合理。
反之,如果为了手机有相机的功能而滥用继承,即让手机继承相机,显然不合常理。


错误地设计

相机类:Camera.java

/**
 * 照相机类,显然只有照相功能
 */
public class Camera {

    public void takephoto() {
        System.out.println("拍照");
    }
}

手机类:Phone.java

/**
 * 手机类,显然有照相功能,这里利用不合理的继承,is a 关系
 */
public class Phone extends Camera{

    public void dial() {
        System.out.println("打电话");
    }
}

音乐手机类:MusicPhone.java

/**
 * 音乐手机类,显然它本身是个手机,继承手机类 is a
 */
public class MusicPhone extends Phone{

    public void play() {
        System.out.println("播放MP3");
    }
}

测试运行

/**
 * 测试不合理的继承:
 * MusicPhone -> Phone -> Camera
 * 尽管可以实现功能,即音乐手机对象同时具备音乐播放、打电话和拍照功能,and 手机对象有打电话和相机功能,都是继承得到的。
 * 但是 Phone 应该不是Camera, 应该考虑聚合 has a
 */
public class Test {

    public static void main(String[] args) {

        MusicPhone cellphoneWithMP3 = new MusicPhone();
        cellphoneWithMP3.dial();
        cellphoneWithMP3.takephoto();
        cellphoneWithMP3.play();

    }

}

结果:

打电话
拍照
播放MP3

正确的设计

主要改变Phone和Camera之间的关系。

相机类:Camera.java,不变

手机类:Phone2.java ,不再继承相机,而是聚合

/**
 * 手机应该聚合相机,手机是拥有照相功能,而不是属于相机,手机has a 相机
 */
public class Phone2 extends Camera{

    public void dial() {
        System.out.println("打电话");
    }
}

音乐手机类:MusicPhone2.java

/**
 *  音乐手机类,显然它本身是个手机,继承手机类 is a
 * 这里可以继承,也可以聚合。因为音乐手机属于手机没毛病
 */
public class MusicPhone extends Phone{

    public void play() {
        System.out.println("播放MP3");
    }
}

测试运行

/**
 * 测试不合理的继承:
 * 纠正不合理的继承:
 * 手机聚合相机,音乐手机继承手机
 */
public class Test2 {
    public static void main(String[] args) {
        MusicPhone2 musicCellphone2 = new MusicPhone2();
        musicCellphone2.play();
        musicCellphone2.dial();
        //musicCellphone2.takephoto(); //这样会报错,因为手机不在是相机,而是聚合相机
        musicCellphone2.camera.takephoto();//注意这里的变化
    }

}

结果:

打电话
拍照
播放MP3

简单架构图

这里写图片描述


最后

参考:Java核心技术卷一 -类之间的关系 和 良葛格的openhomecc

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值