合成复用法则(CRP)规定:在软件复用的时候应该优先使用组合或者聚合的方式实现关联,其次才考虑继承关系实现
如果要使用继承关系,则应该严格遵循里氏替换原则,合成复用和里氏替换原则都是开闭原则的具体实现
合成复用的实现方式有两种
- 继承:继承虽然简单方便,但同时也具备以下缺点
- 继承复用破坏了封装,父类的实现细节暴露给了子类
- 父子类的耦合度高,父类的任何改变都讲牵扯到子类
- 组合或聚合:可以将已有对象加入到新对象中,新对象可以调用已有功能,有以下优点
- 维持了封装,未暴露细节
- 耦合度低,对已有对象的操作都是通过接口调用
组合/聚合:
如下代码:A类中引用了B类,假设A对象消失,如果B对象没有其他引用,则B对象也会被GC,这就是组合。
而如果B对象被其他对象引用了,B对象则不会消失,这就是聚合。
static class A{
B b;
A(B b){
this.b = b;
}
}
static class B{
A a;
B(A a){
this.a = a;
}
}
示例代码:
// 测试
public static void main(String[] args) {
ProductDao productDao = new ProductDao();
productDao.setDbConnection(new PostgreSQLConnection());
productDao.addProduct(); // addPostgresSQL conn
}
// 基类
abstract static class DBConnection {
public abstract String getConnection();
}
// mysql连接
static class MySQLConnection extends DBConnection {
@Override
public String getConnection() {
return "MySQL conn";
}
}
//PG连接
static class PostgreSQLConnection extends DBConnection {
@Override
public String getConnection() {
return "PostgresSQL conn";
}
}
// 组合
static class ProductDao{
private DBConnection dbConnection;
public void setDbConnection(DBConnection dbConnection) {
this.dbConnection = dbConnection;
}
public void addProduct() {
String conn = dbConnection.getConnection();
System.out.println("add" + conn);
}
}