Java设计模式:合成复用原则及迪米特法则应用实例
Java设计模式:合成复用原则及迪米特法则应用实例
合成复用原则
实例说明
某软件公司开发人员在初期的CRM系统设计中,考虑到客户数量不多,系统采用Access作为数据库,与数据库操作有关的类,例如CustomerDAO类等都需要连接数据库,连接数据库的方法getConnection()封装在DBUtil类中,由于需要重用DBUtil类的getConnection()方法,设计人员将CustomerDAO作为DBUtil类的子类,初始设计方案结构如图所示:
(图片)
随着客户数量的增加,系统决定升级为Oracle数据库,因此需要增加一个新的OracleDBUtil类来连接Oracle数据库,由于在初始设计方案中CustomerDAO和DBUtil之间是继承关系,因此在更换数据库连接方式时需要修改CustomerDAO类的源代码,将CustomerDAO作为OracleDBUtil的子类,这将违背开闭原则。当然也可以直接修改DBUtil类的源代码,这同样也违背了开闭原则。以下使用合成复用原则对其进行重构,重构类图参考如下。请根据如下重构类图编程实现。
(图片)
分析与说明:
根据合成复用原则,在实现复用时应该多用关联,少用继承。因此在重构时使用关联复用来取代继承复用。CustomerDAO和DBUtil之间的关第由继承变为关联,采用依赖注入的方式将DBUtil对象注入到CustomerDAO中,可以使用构造注入,也可以使用设值注入。如需对DBUtil的功能进行扩展,可以通过其子类来实现。
代码实现java// DBUtil类public class DBUtil { public Connection getConnection() { // 连接数据库的具体实现 }}
// CustomerDAO类public class CustomerDAO { private DBUtil dbUtil; // 构造注入 public CustomerDAO(DBUtil dbUtil) { this.dbUtil = dbUtil; } // 使用DBUtil对象进行数据库连接 public void connect() { Connection connection = dbUtil.getConnection(); // 其他操作 }}
// OracleDBUtil类public class OracleDBUtil extends DBUtil { @Override public Connection getConnection() { // 连接Oracle数据库的具体实现 }}
// 客户端代码public class Main { public static void main(String[] args) { // 使用Access数据库 DBUtil accessDBUtil = new DBUtil(); CustomerDAO accessCustomerDAO = new CustomerDAO(accessDBUtil); accessCustomerDAO.connect(); // 使用Oracle数据库 DBUtil oracleDBUtil = new OracleDBUtil(); CustomerDAO oracleCustomerDAO = new CustomerDAO(oracleDBUtil); oracleCustomerDAO.connect(); }}
迪米特法则
实例说明
有校学生会成员和院学生会成员,现在需要编程打印所有学生会成员。初始方案如图所示的结构:
(图片)
以上方式解决了问题,但是却违反了迪米特法则。
SchoolManager中的printAllStudentCouncilMember()方法中以局部变量的方式引用了CollegeStudentCouncilMember类,所以在这里CollegeStudentCouncilMember不是SchoolManager的直接朋友。
解决方式:将CollegeStudentCouncilMember变成SchoolManager的直接朋友,可以通过构造器传入、setter方法设置、参数传入等方式解决。
将院学生会成员的打印细节封装到了院管理者内部,对外只暴露出一个printCollegeStudentCouncilMembl()方法.
代码实现java// 抽象学生会成员类public abstract class StudentCouncilMember { private String name; private int id;
// 构造方法、getter和setter方法省略
public abstract void print();}
// 校学生会成员类public class SchoolStudentCouncilMember extends StudentCouncilMember { @Override public void print() { System.out.println('Printing school student council member: ' + getName()); // 打印校学生会成员的具体信息 }}
// 院学生会成员类public class CollegeStudentCouncilMember extends StudentCouncilMember { @Override public void print() { System.out.println('Printing college student council member: ' + getName()); // 打印院学生会成员的具体信息 }}
// 学校管理者类public class SchoolManager { private List
public SchoolManager() { studentCouncilMembers = new ArrayList<>(); }
// 添加学生会成员 public void addStudentCouncilMember(StudentCouncilMember member) { studentCouncilMembers.add(member); }
// 打印所有学生会成员 public void printAllStudentCouncilMembers() { for (StudentCouncilMember member : studentCouncilMembers) { member.print(); } }}
// 院管理者类public class CollegeManager { private List
public CollegeManager() { studentCouncilMembers = new ArrayList<>(); }
// 添加学生会成员 public void addStudentCouncilMember(StudentCouncilMember member) { studentCouncilMembers.add(member); }
// 打印所有学院学生会成员 public void printCollegeStudentCouncilMembers() { for (StudentCouncilMember member : studentCouncilMembers) { member.print(); } }}
// 客户端代码public class Main { public static void main(String[] args) { SchoolManager schoolManager = new SchoolManager(); CollegeManager collegeManager = new CollegeManager();
// 添加校学生会成员 schoolManager.addStudentCouncilMember(new SchoolStudentCouncilMember('John', 1)); schoolManager.addStudentCouncilMember(new SchoolStudentCouncilMember('Emma', 2));
// 添加院学生会成员 collegeManager.addStudentCouncilMember(new CollegeStudentCouncilMember('Tom', 3)); collegeManager.addStudentCouncilMember(new CollegeStudentCouncilMember('Lucy', 4));
// 打印所有学生会成员 schoolManager.printAllStudentCouncilMembers(); collegeManager.printCollegeStudentCouncilMembers(); }}
总结
在上述例子中,我们分别使用合成复用原则和迪米特法则对代码进行了重构。
在第一个例子中,我们使用合成复用原则将CustomerDAO和DBUtil之间的继承关系改为关联关系,通过依赖注入的方式将DBUtil对象注入到CustomerDAO中。这样,当切换数据库时,只需要针对不同的数据库创建不同的DBUtil子类,并将其实例对象注入到CustomerDAO中,无需修改CustomerDAO的源代码,符合开闭原则。
在第二个例子中,我们使用迪米特法则将学院学生会成员的打印细节封装到了院管理者类内部,对外只暴露出一个printCollegeStudentCouncilMembers()方法。这样,SchoolManager类不再直接引用CollegeStudentCouncilMember类,而是通过CollegeManager来间接操作,减少了类之间的耦合性,符合迪米特法则。
原文地址: https://www.cveoy.top/t/topic/PH8 著作权归作者所有。请勿转载和采集!