参考慕课网视频《Java设计模式精讲》:
视频作者:Geely
视频链接:https://coding.imooc.com/lesson/270.html#mid=17156
定义
尽量使用对象组合/聚合,而不是继承关系达到软件复用的目的。
聚合has-A、组合contains-A、继承is-A
优点
可以使系统更加灵活,降低类与类之间的耦合度,一个类的变化对其他类造成的影响相对较少。
代码实现
案例:使用MySQL操作数据库。
首先定义一个获取数据库连接的类。
public class DbConnection {
public String getConnection() {
return "MySQL数据库的连接";
}
}
然后定义一个操作用户的类,让其继承DbConnection
public class UserDao extends DbConnection {
public void addUser() {
String connection = super.getConnection();
System.out.println("使用" + connection + "增加产品");
}
}
最后就是测试类
public class MainTest {
public static void main(String[] args) {
UserDao userDao = new UserDao();
userDao.addUser();
}
}
这样写是没有问题的,但是如果需求变更,客户想要使用Oracle连接数据库了,那怎么办?难道对DbConnection进行修改吗?这样违背了开闭原则。所以使用合成复用原则对代码进行重构。
定义一个抽象类
public abstract class BaseDbConnection {
/**
* 获取数据库简连接
* @return
*/
public abstract String getConnection();
}
编写其实现类,分别定义MySQL和Oracle的数据库连接类,让其继承BaseDbConnection
public class MySqlConnection extends BaseDbConnection {
@Override
public String getConnection() {
return "MySQL数据库连接";
}
}
public class OracleConnection extends BaseDbConnection {
@Override
public String getConnection() {
return "oracle数据库连接";
}
}
然后将数据库连接对象组合进操作用户的数据库访问层UserDao
public class UserDao {
private BaseDbConnection baseDbConnection;
public void setBaseDbConnection(BaseDbConnection baseDbConnection) {
this.baseDbConnection = baseDbConnection;
}
public void addUser() {
String connection = baseDbConnection.getConnection();
System.out.println("使用" + connection + "增加用户");
}
}
最后就是测试方法了。
public static void main(String[] args) {
BaseDbConnection connection = new MySqlConnection();
UserDao userDao = new UserDao();
userDao.setBaseDbConnection(connection);
userDao.addUser();
}
重构的代码符合开闭原则。当需要增加其他产品的数据库时,直接对基类进行扩展就可以了。
同样也是符合合成复用原则的,在setBaseDbConnection()方法中,注入的是BaseDbConnection这个类。因为它是抽象类,不能实例化对象,所以,由其子类来实例化对象。可以选择任意子类来进行实例化。
基本上合成复用原则就讲完了,也是非常简单的。
人的天性之一,就是不会接受别人的批评,总是认为自己永远是对的,喜欢找各种各样的借口为自己辩解。