合成复用原则
# 合成复用原则(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来返回各自的链接;
改用接口的方式实现:

### 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();
}
}
```
## 合成复用的优点
**通常类的复用分为继承复用和合成复用两种;**
继承复用虽然有简单和易实现的优点,但它也存在以下缺点:
- **继承复用破坏了类的封装性**
> 因为继承会将父类的实现细节暴露给子类,父类对子类是透明的,所以这种复用又称为“白箱”复用。
- **子类与父类的耦合度高**
> 父类的实现的任何改变都会导致子类的实现发生变化,这不利于类的扩展与维护。
- **它限制了复用的灵活性**
> 从父类继承而来的实现是静态的,在编译时已经定义,所以在运行时不可能发生变化。
采用组合或聚合复用时,可以将已有对象纳入新对象中,使之成为新对象的一部分,新对象可以调用已有对象的功能,它有以下优点:
- **它维持了类的封装性**
> 因为成分对象的内部细节是新对象看不见的,所以这种复用又称为“黑箱”复用。
- **新旧类之间的耦合度低**
>这种复用所需的依赖较少,新对象存取成分对象的唯一方法是通过成分对象的接口。
- **复用的灵活性高**
>这种复用可以在运行时动态进行,新对象可以动态地引用与成分对象类型相同的对象。