当前位置:首页 > 公众号精选 > 架构师社区
[导读]前言平时我们写代码呢,多数情况都是流水线式写代码,基本就可以实现业务逻辑了。如何在写代码中找到乐趣呢,我觉得,最好的方式就是:使用设计模式优化自己的业务代码。今天跟大家聊聊日常工作中,我都使用过哪些设计模式。工作中常用到哪些设计模式1.策略模式1.1业务场景假设有这样的业务场景,...

前言

平时我们写代码呢,多数情况都是流水线式写代码,基本就可以实现业务逻辑了。如何在写代码中找到乐趣呢,我觉得,最好的方式就是:使用设计模式优化自己的业务代码。今天跟大家聊聊日常工作中,我都使用过哪些设计模式。


实战!工作中常用到哪些设计模式工作中常用到哪些设计模式

1.策略模式

1.1 业务场景

假设有这样的业务场景,大数据系统把文件推送过来,根据不同类型采取不同的解析方式。多数的小伙伴就会写出以下的代码:


if(type=="A"){
//按照A格式解析

}else if(type=="B"){
//按B格式解析
}else{
//按照默认格式解析
}
这个代码可能会存在哪些问题呢?


  • 如果分支变多,这里的代码就会变得臃肿,难以维护,可读性低。
  • 如果你需要接入一种新的解析类型,那只能在原有代码上修改。
说得专业一点的话,就是以上代码,违背了面向对象编程的开闭原则以及单一原则。


  • 开闭原则(对于扩展是开放的,但是对于修改是封闭的):增加或者删除某个逻辑,都需要修改到原来代码
  • 单一原则(规定一个类应该只有一个发生变化的原因):修改任何类型的分支逻辑代码,都需要改动当前类的代码。
如果你的代码就是酱紫:有多个if...else等条件分支,并且每个条件分支,可以封装起来替换的,我们就可以使用策略模式来优化。


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 StrategyUseService implements ApplicationContextAware{


private Map iFileStrategyMap = new ConcurrentHashMap<>();

public void resolveFile(FileTypeResolveEnum fileTypeResolveEnum, Object objectParam) {
IFileStrategy iFileStrategy = iFileStrategyMap.get(fileTypeResolveEnum);
if (iFileStrategy != null) {
iFileStrategy.resolve(objectParam);
}
}

//把不同策略放到map
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
Map tmepMap = applicationContext.getBeansOfType(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");
}
}
}

这段代码使用了异常来做逻辑条件判断,如果后续逻辑越来越复杂的话,会出现一些问题:如异常只能返回异常信息,不能返回更多的字段,这时候需要自定义异常类。


并且,阿里开发手册规定:禁止用异常做逻辑判断。


【强制】 异常不要用来做流程控制,条件控制。说明:异常设计的初衷是解决程序运行中的各种意外情况,且异常的处理效率比条件判断方式要低很多。


如何优化这段代码呢?可以考虑责任链模式


2.2 责任链模式定义

当你想要让一个以上的对象有机会能够处理某个请求的时候,就使用责任链模式。


责任链模式为请求创建了一个接收者对象的链。执行链上有多个对象节点,每个对象节点都有机会(条件匹配)处理请求事务,如果某个对象节点处理完了,就可以根据实际业务需求传递给下一个节点继续处理或者返回处理完毕。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。


责任链模式实际上是一种处理请求的模式,它让多个处理器(对象节点)都有机会处理该请求,直到其中某个处理成功为止。责任链模式把多个处理器串成链,然后让请求在链上传递:


实战!工作中常用到哪些设计模式责任链模式打个比喻:


假设你晚上去上选修课,为了可以走点走,坐到了最后一排。来到教室,发现前面坐了好几个漂亮的小姐姐,于是你找张纸条,写上:“你好, 可以做我的女朋友吗?如果不愿意请向前传”。纸条就一个接一个的传上去了,后来传到第一排的那个妹子手上,她把纸条交给老师,听说老师40多岁未婚...


2.3 责任链模式使用

责任链模式怎么使用呢?


  • 一个接口或者抽象类
  • 每个对象差异化处理
  • 对象链(数组)初始化(连起来)

2.3.1 一个接口或者抽象类

这个接口或者抽象类,需要:


  • 有一个指向责任下一个对象的属性
  • 一个设置下一个对象的set方法
  • 给子类对象差异化实现的方法(如以下代码的doFilter方法)
/**
*  关注公众号:捡田螺的小男孩
*/
public abstract class AbstractHandler {

//责任链中的下一个对象
private AbstractHandler nextHandler;

/**
* 责任链的下一个对象
*/
public void setNextHandler(AbstractHandler nextHandler){
this.nextHandler = nextHandler;
}

/**
* 具体参数拦截逻辑,给子类去实现
*/
public void filter(Request request, Response response) {
doFilter(request, response);
if (getNextHandler() != null) {
getNextHandler().filter(request, response);
}
}

public AbstractHandler getNextHandler() {
return nextHandler;
}

abstract void doFilter(Request filterRequest, Response response);

}

2.3.2 每个对象差异化处理

责任链上,每个对象的差异化处理,如本小节的业务场景,就有参数校验对象、安全校验对象、黑名单校验对象、规则拦截对象


/**
* 参数校验对象
**/
@Component
@Order(1) //顺序排第1,最先校验
public class CheckParamFilterObject extends AbstractHandler {

@Override
public void doFilter(Request request, Response response) {
System.out.println("非空参数检查");
}
}

/**
*  安全校验对象
*/
@Component
@Order(2) //校验顺序排第2
public class CheckSecurityFilterObject extends AbstractHandler {

@Override
public void doFilter(Request request, Response response) {
//invoke Security check
System.out.println("安全调用校验");
}
}
/**
*  黑名单校验对象
*/
@Component
@Order(3) //校验顺序排第3
public class CheckBlackFilterObject extends AbstractHandler {

@Override
public void doFilter(Request request, Response response) {
//invoke black list check
System.out.println("校验黑名单");
}
}

/**
*  规则拦截对象
*/
@Component
@Order(4) //校验顺序排第4
public class CheckRuleFilterObject extends AbstractHandler {

@Override
public void doFilter(Request request, Response response) {
//check rule
System.out.println("check rule");
}
}


本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
关闭
关闭