设计原则 - 合成复用原则
概念
- 合成复用原则(Composite Reuse Principle, CRP):尽量使用对象组合(contains-A)/聚合(has-A),而不是继承关系达到软件复用的目的。
- 合成复用原则就是在一个新的对象里通过关联关系(包括组合关系和聚合关系)来使用一些已有的对象,使之成为新对象的一部分;新对象通过委派调用已有对象的方法达到复用功能的目的。
- 优点:可以使系统更加灵活,降低类与类之间的耦合度,一个类的变化对其他类造成的影响相对较少。
- 合成复用是达到开闭原则的一种实现方式。
编码
实例
- 数据库连接,采用
mysql
作为数据库 DBConnection.java
/**
* @Description DB连接
* @date Dec 19, 2021
* @version 1.0
*/
public class DBConnection {
/**
* 获取DB连接
* @return
*/
public String getConnection() {
return "Mysql数据库连接";
}
}
ProductDao.java
/**
* @Description 产品DAO
* @date Dec 19, 2021
* @version 1.0
*/
public class ProductDao extends DBConnection {
/**
* 添加产品
*/
public void addProduct() {
String conn = super.getConnection();
System.out.println("使用" + conn + "增加产品");
}
}
Test.java
/**
* @Description 测试类
* @date Dec 19, 2021
* @version 1.0
*/
public class Test {
public static void main(String[] args) {
ProductDao productDao = new ProductDao();
productDao.addProduct();
}
}
- 输出:
使用Mysql数据库连接增加产品
- 类图如下:
- 由于在初始设计方案中
DBConnection
和ProductDao
之间是继承关系,因此在更换数据库连接方式时需要修改DBConnection
或ProductDao
的源代码,这将违反开闭原则
合成复用原则
-
实现数据库连接的扩展性,使用关联复用来取代继承复用
-
DBConnection.java
/**
* @Description DB连接
* @date Dec 19, 2021
* @version 1.0
*/
public abstract class DBConnection {
/**
* 获取DB链接
* @return
*/
public abstract String getConnection();
}
MysqlConnection.java
/**
* @Description Mysql连接
* @date Dec 20, 2021
* @version 1.0
*/
public class MysqlConnection extends DBConnection {
@Override
public String getConnection() {
return "Mysql数据库连接";
}
}
OracleConnection.java
/**
* @Description Oracle连接
* @date Dec 20, 2021
* @version 1.0
*/
public class OracleConnection extends DBConnection {
@Override
public String getConnection() {
return "Oracle数据库连接";
}
}
ProductDao.java
/**
* @Description 产品DAO
* @date Dec 19, 2021
* @version 1.0
*/
public class ProductDao {
private DBConnection dbConnection;
/**
* setter注入
* @param dbConnection
*/
public void setDbConnection(DBConnection dbConnection) {
this.dbConnection = dbConnection;
}
/**
* 添加产品
*/
public void addProduct() {
String conn = dbConnection.getConnection();
System.out.println("使用" + conn + "增加产品");
}
}
Test.java
/**
* @Description 合成复用原则测试类
* @author Coisini
* @date Dec 19, 2021
* @version 1.0
*/
public class Test {
public static void main(String[] args) {
ProductDao productDao = new ProductDao();
productDao.setDbConnection(new MysqlConnection());
productDao.addProduct();
productDao.setDbConnection(new OracleConnection());
productDao.addProduct();
}
}
- 输出:
使用Mysql数据库连接增加产品
使用Oracle数据库连接增加产品
- 类图变化如下:
ProductDao
与DBConnection
的关系由继承关系变为关联关系,采用依赖注入的方式将DBConnection
对象注入到ProductDao
中,DBConnection
的扩展通过其子类实现,根据里氏替换原则,DBConnection
的子类可以覆盖DBConnection
对象,只需在ProductDao
中注入DBConnection
的子类对象即可使用子类所扩展的方法,通过这种方式,原有代码无需修改,还可以灵活的增加新的数据库连接方式。