开放封闭原则有两个特性:
1.面对扩展开放。可以以最小的代价支持需求变更。
2.面对修改封闭。需求的变更不会对原代码造成侵略。
这篇文就来记录一下关于开放封闭原则的实践。
使用场景
在业务中存在某一领域的实体会被其实多个实体引用的情况,在删除这一实体时需要校验是否有被引用,如果被引用则不可以被删除。
比如这种情况:在一个培训系统中,存在N个某个站点的老师,和N个这一站点的班级。那站点就是同时被老师与班级引用了,当在系统中需要删除站点的时候,就需要判断这个站点上是否还存在有效的老师和班级。
创建实体
/**
* 站点实体
*/
public class Site{
// 站点ID
private Long siteId;
// 站点名称
private String siteName;
}
/**
* 老师实体
*/
public class teacher{
// 老师ID
private Long teacherId;
// 老师名称
private String teacherName;
// 所属站点
private Long siteId;
}
/**
* 班级实体
*/
public class classes{
// 班级ID
private Long classId;
// 班级名称
private String className;
// 所属站点
private Long siteId;
}
传统做法
在这种情况下的传统做法可能是这样的。在删除站点的接口,依次查询当前站点下的老师和班级,存在即不可删除。
创建查询方法
/**
* 查询当前站点下的老师
*/
public class teacherManager{
public Boolean checkExistTeacherBySite(Long siteId){
// 根据站点查询老师
// select count(*) from teacher_table where site_id = siteId and status =0;
Long count = 查询结果;
return count > 0 ;
}
}
/**
* 查询当前站点下的班级
*/
public class classesManager{
public Boolean checkExistClassesBySite(Long siteId){
// 根据站点查询班级
// select count(*) from class_table where site_id = siteId and status = 0;
Long count = 查询结果;
return count > 0 ;
}
}
删除站点
public class siteManager{
public Boolean deleteSite(Long siteId){
if (!checkExistTeacherBySite && !checkExistClassesBySite){
// 一般为逻辑删除,这里为了示意。
return deleteByPrimaryKey(siteId);
}else {
log.warn("站点已被引用,不能删除");
return false;
}
}
}
缺点
这种方法的弊端相信很容易就看出来了,就是不利于扩展,如果以后又增加例如实操训练、考试任务等需求需要关联站点,那就还需要更改删除站点的这一方法。不光如此,站点这一实体的特性属于基础信息,在实际项目中可能存在关联很多实体,那造成的结果就会if中的判断一长串,非常不美观。
这种做法既不能保持代码的整洁,也不满足java的面向对象原则。
优化做法
创建实体的部分是一样的,区别在于查找被引用的实体。
创建接口
public interface SiteReferceChecker{
/**
* 查看站点是否被引用
*/
Boolean checkSiteUsed(Long siteId);
}
引用实现
/**
* 在老师实体中查看当前站点是否被引用
*/
public class teacherManager implements SiteReferceChecker{
public Boolean checkSiteUsed(Long siteId){
// 根据站点查询老师
// select count(*) from teacher_table where site_id = siteId and status =0;
Long count = 查询结果;
return count > 0 ;
}
}
/**
* 在班级实体中查看当前站点是否被引用
*/
public class classesManager implements SiteReferceChecker{
public Boolean checkSiteUsed(Long siteId){
// 根据站点查询班级
// select count(*) from class_table where site_id = siteId and status = 0;
Long count = 查询结果;
return count > 0 ;
}
}
删除站点
public class siteManager{
// 通过自动注入找到所有被引用的点
@Resouse
private List<SiteReferceChecker> checkers;
public Boolean deleteSite(Long siteId){
if (isSiteUsed(siteId)){
log.warn("站点已被引用,不能删除");
return false;
}
// 一般为逻辑删除,这里为了示意。
return deleteByPrimaryKey(siteId);
}
private isSiteUsed(Long siteId){
if (CollectionUtils.isEmpty(checkers)){
return false;
}
// 循环所有引用点,查看是否被引用
for (SiteReferceChecker checker : checkers) {
if (checker.checkSiteUsed(siteId)) {
return true;
}
}
return false;
}
}
总结
在根据开放封闭原则优化后的实现的优化是显而易见的,当有需求变化,例如增加了考试关联站点时,那只需要在考试的类中实现SiteReferceChecker的checkSiteUsed方法,就可以了,站点中的删除方法会自动查找所有引用点,完成校验。