合成复用原则

# 合成复用原则(Composite Reuse Principle) ## 合成复用的定义 合成复用原则又叫做组合、聚合复用原则,它要求在软件复用时,尽量先使用组合和聚合等关系来实现, 其次才考虑使用继承关系来实现; 如果要使用继承关系,则必须严格遵循里氏替换原则,合成复用原则同里氏替换原则相辅相成; ## 举个例子 定义一个数据库连接类,然后写一个Dao方法去插入一条商品信息到数据库中; 这个需求中,ProductDao类不能继承自数据库链接类,这样ProductDao会得到DbConnection其他大量无用的信息, 这是不符合迪米特法则的; ### DbConnection ```text public class DbConnection { public String getConnection(){ return "Mysql connection!"; } } ``` ### ProductDao ``` public class ProductDao { private DbConnection dbConnection; public ProductDao(DbConnection dbConnection) { this.dbConnection = dbConnection; } public void addProduct(){ System.err.println("Add a product!"); String connection = dbConnection.getConnection(); System.err.println("Db connection is :" + connection); } } ``` 而且数据库有很多种,Mysql、Oracle等数据库的链接可能各有差异,所以需要分别实现DbConnection来返回各自的链接; 改用接口的方式实现: ![](https://oscimg.oschina.net/oscnet/up-5a3cfcbb2107d037e34f61aef84873fdd9e.png) ### DbConnection接口 ```text public interface DbConnection { String getConnection(); } ``` ### MysqlConnection 数据库链接 ```text public class MysqlConnection implements DbConnection{ @Override public String getConnection() { return "Mysql connection"; } } ``` ### Oracle 数据库链接 ```text public class OracleConnection implements DbConnection{ @Override public String getConnection() { return "Oracle connection"; } } ``` ### 测试类 ```text public class DemoTest { public static void main(String[] args) { ProductDao productDao = new ProductDao(new OracleConnection()); productDao.addProduct(); } } ``` ## 合成复用的优点 **通常类的复用分为继承复用和合成复用两种;** 继承复用虽然有简单和易实现的优点,但它也存在以下缺点: - **继承复用破坏了类的封装性** > 因为继承会将父类的实现细节暴露给子类,父类对子类是透明的,所以这种复用又称为“白箱”复用。 - **子类与父类的耦合度高** > 父类的实现的任何改变都会导致子类的实现发生变化,这不利于类的扩展与维护。 - **它限制了复用的灵活性** > 从父类继承而来的实现是静态的,在编译时已经定义,所以在运行时不可能发生变化。 采用组合或聚合复用时,可以将已有对象纳入新对象中,使之成为新对象的一部分,新对象可以调用已有对象的功能,它有以下优点: - **它维持了类的封装性** > 因为成分对象的内部细节是新对象看不见的,所以这种复用又称为“黑箱”复用。 - **新旧类之间的耦合度低** >这种复用所需的依赖较少,新对象存取成分对象的唯一方法是通过成分对象的接口。 - **复用的灵活性高** >这种复用可以在运行时动态进行,新对象可以动态地引用与成分对象类型相同的对象。