优先使用对象组合,而不是通过继承来达到复用的目的。
某软件公司开发人员在初期的 CRM (客户关系管理)系统设计中考虑到客户数量不多。系统采用 Access 作为数据库,与数据库操作有关的类(例如 CustomerDAO 类等)都需要连接致据库,连接数据库的方法 getConnection() 封装在 DBUtil 类中,由于需要重用 DBUtil 类的 getConnection() 方法,设计人员将 CustomerDAO 作为 DBUtil 类的子类,初始设计方案结构如下图所示。
随着客户数量的增加,系统决定升级为 Oracle 数据库。因此需要增加一个新的 OracleDBUtil 类来连接 Oracle 数据库。由于在初始设计方案中 CustomerDAO 和 DBUtil 之间是继承关系。因此在更换数据库连接方式时需要修改 CustomerDAO 类的源代码。将 CustomerDAO 作为 OracleDBUtil 的子类,这将违反开闭原则。当然也可以直接修改 DBUtil 类的源代码,这同样也违反了开闭原则。
现使用合成复用原则对其进行重构。
解析(参考):
根据合成复用原则,在实现复用时应该多用关联,少用继承。因此在本实例中可以使用关联复用来取代继承复用,重构后的结构如图所示。
在图中,CustomerDAO 和 DBUtil 之间的关系由继承关系变为关联关系,采用依赖注入的方式将 DBUtil 对象注入到 CustomerDAO 中,可以使用构造注入,也可以使用设值注入。如果需要对 DBUtil 的功能进行扩展,可以通过其子类来实现,例如通过子类OracleDBUtil 来连接 Oracle 数据库。由于 CustomerDAO 针对 DBUtil 编程,根据里氏代换原则,DBUtil 子类的对象可以覆盖 DBUtil 对象,只需在 CustomerDAO 中注人子类对象即可使用子类所扩展的方法。例如在 CustomerDAO 中注入 OracleDBUtil 对象,即可实现Oracle 数据库连接,原有代码无须进行修改,而且可以很灵活地增加新的数据库连接方式,符合开闭原则。