实战!⼯作中常⽤到哪些设计模式
平时我们写代码呢,多数情况都是流⽔线式写代码,基本就可以实现业务逻辑了。如何在写代码中找到乐趣呢,我觉得,最好的⽅式就是:使⽤设计模式优化⾃⼰的业务代码。今天跟⼤家聊聊⽇常⼯作中,我都使⽤过哪些设计模式。
1.策略模式
1.1 业务场景
假设有这样的业务场景,⼤数据系统把⽂件推送过来,根据不同类型采取不同的解析⽅式。多数的⼩伙伴就会写出以下的代码:
if(type=="A"){
//按照A格式解析
}el if(type=="B"){
//按B格式解析
}el{
//按照默认格式解析
}
这个代码可能会存在哪些问题呢?
如果分⽀变多,这⾥的代码就会变得臃肿,难以维护,可读性低。
如果你需要接⼊⼀种新的解析类型,那只能在原有代码上修改。
说得专业⼀点的话,就是以上代码,违背了⾯向对象编程的开闭原则以及单⼀原则。
开闭原则(对于扩展是开放的,但是对于修改是封闭的):增加或者删除某个逻辑,都需要修改到原来代码
单⼀原则(规定⼀个类应该只有⼀个发⽣变化的原因):修改任何类型的分⽀逻辑代码,都需要改动当前类的代码。
如果你的代码就是酱紫:有多个if...el等条件分⽀,并且每个条件分⽀,可以封装起来替换的,我们就可以使⽤策略模式来优化。
1.2 策略模式定义
策略模式定义了算法族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化独⽴于使⽤算法的的客户。这个策略模式的定义是不是有点抽象呢?那我们来看点通俗易懂的⽐喻:
假设你跟不同性格类型的⼩姐姐约会,要⽤不同的策略,有的请电影⽐较好,有的则去吃⼩吃效果不错,有的去逛街买买买最合适。当然,⽬的都是为了得到⼩姐姐的芳⼼,请看电影、吃⼩吃、逛街就是不同的策略。
策略模式针对⼀组算法,将每⼀个算法封装到具有共同接⼝的独⽴的类中,从⽽使得它们可以相互替换。
1.3 策略模式使⽤
学的成语策略模式怎么使⽤呢?酱紫实现的:
⼀个接⼝或者抽象类,⾥⾯两个⽅法(⼀个⽅法匹配类型,⼀个可替换的逻辑实现⽅法)
不同策略的差异化实现(就是说,不同策略的实现类)
使⽤策略模式
1.3.1 ⼀个接⼝,两个⽅法
public interface IFileStrategy {
/
/属于哪种⽂件解析类型
FileTypeResolveEnum gainFileType();
//封装的公⽤算法(具体的解析⽅法)
void resolve(Object objectparam);
}
1.3.2 不同策略的差异化实现
A 类型策略具体实现通大附中
@Component
public class AFileResolve implements IFileStrategy {
@Override
public FileTypeResolveEnum gainFileType() {
return FileTypeResolveEnum.File_A_RESOLVE;
}
@Override
public void resolve(Object objectparam) {
logger.info("A 类型解析⽂件,参数:{}",objectparam);
//A类型解析具体逻辑
}
}
B 类型策略具体实现
@Component
public class BFileResolve implements IFileStrategy {
@Override
public FileTypeResolveEnum gainFileType() {
return FileTypeResolveEnum.File_B_RESOLVE;山的诗句
}
@Override
public void resolve(Object objectparam) {
logger.info("B 类型解析⽂件,参数:{}",objectparam);
//B类型解析具体逻辑
}
}
默认类型策略具体实现
@Component
public class DefaultFileResolve implements IFileStrategy {
@Override
public FileTypeResolveEnum gainFileType() {
return FileTypeResolveEnum.File_DEFAULT_RESOLVE;
}
@Override
public void resolve(Object objectparam) {
logger.info("默认类型解析⽂件,参数:{}",objectparam);
//默认类型解析具体逻辑
}
}
1.3.3 使⽤策略模式
如何使⽤呢?我们借助spring的⽣命周期,使⽤ApplicationContextAware接⼝,把对⽤的策略,初始化到map⾥⾯。然后对外提供resolveFile⽅法即可。
/**
* @author 公众号:捡⽥螺的⼩男孩
*/
@Component
public class StrategyUService implements ApplicationContextAware{
private Map<FileTypeResolveEnum, IFileStrategy> iFileStrategyMap = new ConcurrentHashMap<>();
public void resolveFile(FileTypeResolveEnum fileTypeResolveEnum, Object objectParam) {
IFileStrategy iFileStrategy = (fileTypeResolveEnum);
if (iFileStrategy != null) {
}
}
//把不同策略放到map
@Override
public void tApplicationContext(ApplicationContext applicationContext) throws BeansException {
Map<String, IFileStrategy> tmepMap = BeansOfType(IFileStrategy.class);
tmepMap.values().forEach(strategyService -> iFileStrategyMap.put(strategyService.gainFileType(), strategyService));
}
}
2. 责任链模式
2.1 业务场景
我们来看⼀个常见的业务场景,下订单。下订单接⼝,基本的逻辑,⼀般有参数⾮空校验、安全校验、⿊名单校验、规则拦截等等。很多伙伴会使⽤异常来实现:
public class Order {
public void checkNullParam(Object param){
//参数⾮空校验
throw new RuntimeException();
}
public void checkSecurity(){
//安全校验
throw new RuntimeException();
}
public void checkBackList(){
//⿊名单校验
throw new RuntimeException();
}
public void checkRule(){
//规则拦截
throw new RuntimeException();
}
public static void main(String[] args) {
Order order= new Order();
try{
order.checkNullParam();
order.checkSecurity ();
order.checkBackList();
order2.checkRule();
System.out.println("order success");
}catch (RuntimeException e){
System.out.println("order fail");
大锅菜的做法
}
}
}
这段代码使⽤了异常来做逻辑条件判断,如果后续逻辑越来越复杂的话,会出现⼀些问题:如异常只能返回异常信息,不能返回更多的字段,这时候需要⾃定义异常类。
并且,阿⾥开发⼿册规定:禁⽌⽤异常做逻辑判断。
【强制】异常不要⽤来做流程控制,条件控制。说明:异常设计的初衷是解决程序运⾏中的各种意外情况,且异常的处理效率⽐条件判断⽅式要低很多。
如何优化这段代码呢?可以考虑责任链模式
VDT2.2 责任链模式定义
手机谜语当你想要让⼀个以上的对象有机会能够处理某个请求的时候,就使⽤责任链模式。
责任链模式为请求创建了⼀个接收者对象的链。执⾏链上有多个对象节点,每个对象节点都有机会(条件匹配)处理请求事务,如果某个对象节点处理完了,就可以根据实际业务需求传递给下⼀个节点继续处理或者返回处理完毕。这种模式给予请求的类型,对请求的发送者和接收者进⾏解耦。
责任链模式实际上是⼀种处理请求的模式,它让多个处理器(对象节点)都有机会处理该请求,直到其中某个处理成功为⽌。责任链模式把多个处理器串成链,然后让请求在链上传递:
责任链模式
打个⽐喻:
假设你晚上去上选修课,为了可以⾛点⾛,坐到了最后⼀排。来到教室,发现前⾯坐了好⼏个漂亮的⼩姐姐,于是你找张纸条,写上:“你好,可以做我的⼥朋友吗?如果不愿意请向前传”。纸条就⼀个接⼀个的传上去了,后来传到第⼀排的那个妹⼦⼿上,她把纸条交给⽼师,听说⽼师40多岁未婚...
2.3 责任链模式使⽤
责任链模式怎么使⽤呢?
⼀个接⼝或者抽象类
每个对象差异化处理
对象链(数组)初始化(连起来)
2.3.1 ⼀个接⼝或者抽象类
这个接⼝或者抽象类,需要:
有⼀个指向责任下⼀个对象的属性
⼀个设置下⼀个对象的t⽅法
给⼦类对象差异化实现的⽅法(如以下代码的doFilter⽅法)
/**
* 关注公众号:捡⽥螺的⼩男孩中班区域活动目标
*/
public abstract class AbstractHandler {
//责任链中的下⼀个对象
private AbstractHandler nextHandler;
/
**
* 责任链的下⼀个对象
*/
public void tNextHandler(AbstractHandler nextHandler){
数学手抄报五年级
}
/**
* 具体参数拦截逻辑,给⼦类去实现
*/
public void filter(Request request, Respon respon) {
doFilter(request, respon);
if (getNextHandler() != null) {
getNextHandler().filter(request, respon);
}
}
public AbstractHandler getNextHandler() {
return nextHandler;
}
abstract void doFilter(Request filterRequest, Respon respon);
}
2.3.2 每个对象差异化处理
责任链上,每个对象的差异化处理,如本⼩节的业务场景,就有参数校验对象、安全校验对象、⿊名单校验对象、规则拦截对象/**
* 参数校验对象
**/
@Component
@Order(1) //顺序排第1,最先校验
public class CheckParamFilterObject extends AbstractHandler {
@Override
public void doFilter(Request request, Respon respon) {
System.out.println("⾮空参数检查");
}
}
/**
* 安全校验对象
*/
@Component
@Order(2) //校验顺序排第2
public class CheckSecurityFilterObject extends AbstractHandler {
@Override
public void doFilter(Request request, Respon respon) {
//invoke Security check
System.out.println("安全调⽤校验");
}
}
/
**
* ⿊名单校验对象
*/
@Component
@Order(3) //校验顺序排第3
public class CheckBlackFilterObject extends AbstractHandler {
@Override
public void doFilter(Request request, Respon respon) {
//invoke black list check
System.out.println("校验⿊名单");
}
}
/**
* 规则拦截对象
*/
@Component
@Order(4) //校验顺序排第4
public class CheckRuleFilterObject extends AbstractHandler {
@Override
public void doFilter(Request request, Respon respon) {
//check rule
System.out.println("check rule");
}
}
2.3.3 对象链连起来(初始化)&& 使⽤
@Component("ChainPatternDemo")
public class ChainPatternDemo {
//⾃动注⼊各个责任链的对象
@Autowired
private List<AbstractHandler> abstractHandleList;
private AbstractHandler abstractHandler;
//spring注⼊后⾃动执⾏,责任链的对象连接起来
@PostConstruct
public void initializeChainFilter(){