05.设计原则之合成复用原则

合成复用原则

定义

尽量使用对象组合,而不是继承来达到复用的目的

合成复用原则就是指在一个新的对象里通过关联关系(包括组合关系和聚合关系)来使用一些已有的对象,使之成为新对象的一部分;
新对象通过委派调用已有对象的方法达到复用其已有功能的目的。
简而言之:要尽量使用组合/聚合关系,少用继承。

分析

在面向对象设计中,可以通过两种基本方法在不同的环境中复用已有的设计和实现,即通过组合/聚合关系或者通过继承。

继承复用("白箱"复用)

继承可能是类之间最明显、最简便的代码复用方式。如果你有两个代码相同的类,就可以为它们创建一个通用的基类,然后将相似的代码移到其中
有效的使用继承会有助于对问题的理解,降低复杂度,而滥用继承反而会增加系统构建和维护的难度以及系统的复杂度,所以
我们要慎重使用继承复用,继承复用会使代码很多问题:

1. 子类不能减少超类的接口
  
   你必须实现父类中所有的抽象方法,即使它们没什么用

2. 在重写方法时,你需要确保新行为与其基类中的版本兼容

   这一点很重要,因为子类的所有对象都可能被传递给以超类对象为参数的任何代码,相信你不会希望这些代码崩溃的
   
3. 继承打破了超类的封装

   因为子类拥有访问父类内部详细内容的权限。此外还可能会有相反的情况出现,那就是程序员为了进一步扩展的方便而让超类知晓子类的内部详细内容。

4. 子类与超类紧密耦合

   超类中的任何修改都可能会破坏子类的功能
   
5. 通过继承复用代码可能导致平行继承体系的产生
   继承通常仅发生在一个维度中。只要出现了两个以上的维度,你就必须创建数量巨大的类组合,从而使类层次结构膨胀到不可思议的程度。

组合/聚合复用("黑箱"复用)

组合是代替继承的一种方法。继承代表类之间的"是"关系(汽车是交通工具)而组合则代表"有"关系(汽车有一个引擎);聚合(一种更松弛组合变体
一个对象可引用另一个对象,但并不管理其生命周期)例如:一辆汽车上有司机,但是司机也可能会使用另一辆汽车,或者选择步行而不使用汽车
这样的话耦合相对较低,选择性地调用成员对象的操作;可以在运行时动态进行。组合/聚合可以系统更加灵活,类与类之间的耦合度降低,一个类
的变化对其他类造成的影响相对较少,因此首先组合/聚合来实现复用;依赖注入,就是合成复用原则最具代表性、最经典的案例体现。如下代码

@RestController
public class LoginController {
    // 依赖注入
    @Autowired
    private LoginService loginService;
    public void login() {
        loginService.login();
    }

} 

试想,如果你使用继承复用的话,就会出现如下"怪怪"的代码

@RestController
public class LoginController extends LoginService {
    public void login() {
        super.login();
    }
}

辩证思考

难道合成复用原则下,所有的代码都不使用继承了吗

首先要理解类继承和接口实现的核心思想,两个能够成为父子关系的类或接口必然有相似的特性,或者有扩展的需要,如子类LinkedHashMap与父类HashMap
且子类都进行了扩展操作。然而上述的LoginController代码仅仅就是为了调用一下LoginService中的方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值