开闭原则,在面向对象编程领域中,规定“软件中的对象(类,模块,函数等等)应该对于扩展是开放的,但是对于修改是封闭的”,这意味着一个实体是允许在不改变它的源代码的前提下变更它的行为。该特性在产品化的环境中是特别有价值的,在这种环境中,改变源代码需要代码审查,单元测试以及诸如此类的用以确保产品使用质量的过程。遵循这种原则的代码在扩展时并不发生改变,因此无需上述的过程。
开闭原则的核心思想是面向抽象编程,定义出接口并实现其方法,通过继承方式进行扩展,都可以体现出开闭原则。
通过订阅哪吒专栏的场景说明一下。
1、普通用户,一般只能查阅哪吒的普通文章,并通过超链的形式时刻提醒着它们,要购买哪吒的付费专栏,付费知识就是香。
2、专属用户,通过购买专栏的形式查阅单一专栏的优质文章,并时刻提醒着,要购买其它专栏啊,毕竟学习才是王道。
3、VIP用户(订阅了哪吒的全部专栏),既可以看《Java基础教程系列》,也可以看《Spring Boot 进阶实战》,无推广,告别CRUD,进阶高级Java工程师,升职加薪,迎娶白富美。
定义要实现的功能,阅读文章、推广选择。
package com.guor.service;
public interface IUserService {
// 阅读文章
void read();
// 推广宣传
void promote();
}
package com.guor.service.impl;
import com.guor.service.IUserService;
/**
* 普通用户
*/
public class GeneralUserServiceImpl implements IUserService {
public void read() {
System.out.println("可以查阅哪吒的普通文章");
}
public void promote() {
System.out.println("并通过超链的形式时刻提醒着它们,要购买哪吒的付费专栏,付费知识就是香");
}
}
package com.guor.service.impl;
import com.guor.service.IUserService;
/**
* 专属用户
*/
public class ExclusiveUserServiceImpl implements IUserService {
public void read() {
System.out.println("通过购买专栏的形式查阅单一专栏的优质文章");
}
public void promote() {
System.out.println("并通过超链的形式时刻提醒着它们,购买哪吒的其它付费专栏,付费知识就是香");
}
}
package com.guor.service.impl;
import com.guor.service.IUserService;
/**
* VIP用户
*/
public class VipUserServiceImpl implements IUserService {
public void read() {
System.out.println("脚踩风火轮,手拿乾坤圈,学习哪吒优质文章,我命由我不由天。");
}
public void promote() {
System.out.println("告别CRUD,进阶高级Java工程师,升职加薪,迎娶白富美");
}
}
每种用户对应的阅读权限都有对应的实现类,不会相互干扰。当某一类用户需要添加新的权限或增加新的用户类别时,操作起来也非常方便。比如上文中提到的逢年过节的要给哪吒VIP发放福利,比如赠送精美图书,赠送精美周边等。
通过利用单一职责原则优化后,现在每个类只负责自己的用户行为,后续无论扩展新的功能还是增加用户种类,都可以很方便的开发和维护。
在项目开发的过程中,尽可能保证接口的定义、类的实现保持单一职责,对项目后期的迭代和维护会有很大的帮助。
那么此时,如果想对VIP用户的权益进行升级,需要扩展,接下来就通过这个场景来体现开闭原则。
如果不考虑开闭原则,也不思考这种方法在整个工程服务中的使用情况,没直接修改VipUserServiceImpl
实现类即可。
package com.guor.service.impl;
import com.guor.service.IUserService;
/**
* VIP用户
*/
public class VipUserServiceImpl implements IUserService {
public void read() {
System.out.println("脚踩风火轮,手拿乾坤圈,学习哪吒优质文章,我命由我不由天。");
}
public void promote() {
System.out.println("新增VIP会员免费送书权益");
}
}
按照开闭原则实现起来并不复杂,它的主要目的是不能因为个例需求的变化而改变写好的实现类,除非之前的实现类有错误。
实现过程式继承父类扩展需要的方法,同时可以保留原有的方法,新增自己需要的方法。
package com.guor.service.impl;
public class VipUserServiceExt extends VipUserServiceImpl {
@Override
public void promote() {
System.out.println("新增VIP会员免费送书权益");
}
}
扩展后的方法已经将VIP会员的权益进行了提升,需要此方法,用户可以直接调用,而其它方法,如查阅哪吒全部文章,则可以继续使用。