很多人觉得自己写的是业务代码,按照逻辑写下去,再把公用的方法抽出来复用就可以了,设计模式根本就没必要用,更没必要学。

一开始的时候,我也是这么想,直到我遇到。。。

举个例子

我们先看一个普通的下单拦截接口。

基本逻辑,参数安全拦截,次数拦截,规则拦截,都通过,返回允许下单,任意一个失败,返回对应的失败原因。

多层嵌套if写法

我们正常多层嵌套if的写法

/**
 * @author saier
 * @date 2020/3/31 18:03
 */
public class Order {
    public Message interrupt1(){
        return null;
    }
    public Message interrupt2(){
        return null;
    }
    public Message interrupt3(){
        return null;
    }
    public Message interrupt4(){
        return null;
    }
    public Message interrupt5(){
        return null;
    }

    public static void main(String[] args) {
        Order order= new Order();
        if(order.interrupt1().getResult() == 1){
            if(order.interrupt2().getResult() == 1){
                if(order.interrupt3().getResult() == 1){
                    if(order.interrupt4().getResult() == 1){
                        if(order.interrupt5().getResult() == 1){
                            System.out.println("success");
                        }
                    }
                }
            }
        }

    }
}

@Data
class Message {
    private int result;
    private String msg;
}

异常处理逻辑

或者有些利用异常做逻辑,代码会简单一点

/**
 * @author saier
 * @date 2020/3/31 18:03
 */
public class Order2 {
    public void interrupt1(){

    }
    public void interrupt2(){

    }
    public void interrupt3(){
        //失败
        throw new RuntimeException();
    }
    public void interrupt4(){
        //失败
        throw new RuntimeException();
    }
    public void interrupt5(){
        //失败
        throw new RuntimeException();
    }

    public static void main(String[] args) {
        Order2 order2= new Order2();
        try{
            order2.interrupt1();
            order2.interrupt2();
            order2.interrupt3();
            order2.interrupt4();
            order2.interrupt5();
            System.out.println("success");
        }catch (RuntimeException e){
            System.out.println("fail");
        }

    }
}

一开始,我就直接使用异常来做逻辑。但后续逻辑越来越复杂之后,也会出现一些问题。例如异常只能返回异常信息,不能返回更多的字段信息。

后面也留意到,异常做逻辑,在阿里规范是禁止的。

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

更重要的是,代码可读性太差了,随时一个方法的异常抛出来,还要考虑代码本身的异常。

没更好的办法,只能考虑设计模式了

怎么改,会使代码的可读性高,扩展性好?

在同事的提醒下,突然想起了设计模式!

我们希望达到的目的

  1. 代码没有这么多if else嵌套,可读性高
  2. 如果新增新的拦截逻辑简单方便,不影响原本的逻辑,扩展性好
  3. 可以很方便地调换拦截逻辑顺序,低耦合

责任链模式

在这种场景下,非常适合责任链模式。(什么场景使用什么设计模式,这就需要平时有积累,知道各种设计模式的基本使用)

责任链,顾名思义,就是用来处理相关事务责任的一条执行链,执行链上有多个节点,每个节点都有机会(条件匹配)处理请求事务,如果某个节点处理完了就可以根据实际业务需求传递给下一个节点继续处理或者返回处理完毕。

首先,建立过滤器的抽象类

public abstract class AbstractFilter {

    private AbstractFilter nextFilter;

    /**
     * 责任链的下一个元素
     */
    public void setNextFilter(AbstractFilter nextFilter){
        this.nextFilter = nextFilter;
    }

    public AbstractFilter getLastFilter(){
        if(this.nextFilter != null){
            return this.nextFilter.getLastFilter();
        }else{
            return this;
        }
    }

    public void filter(FilterRequest filterRequest, Response response){
        doFilter(filterRequest,response);
        if(response.isFilterNext() && nextFilter != null){
            nextFilter.filter(filterRequest,response);
        }
    }

    /**
     * 具体拦截逻辑
     */
    public abstract void doFilter(FilterRequest filterRequest, Response response);

    /**
     * 根据拦截结果做处理
     */
    public void exec(FilterRequest filterRequest, Response response){
    }
}

过滤器的实现类

@Component
@Order(5)
public class CheckParamFilter1 extends AbstractFilter {
    @Override
    public void doFilter(FilterRequest filterRequest, Response response) {

    }
}

@Component
@Order(10)
public class CheckParamFilter2 extends AbstractFilter {
    @Override
    public void doFilter(FilterRequest filterRequest, Response response) {

    }
}

使用Order注解,确定过滤器的顺序,后续在spring注入的时候,会有奇效

//利用spring的自动注入机制
@Autowired
List<AbstractFilter> abstractFilterList;

private AbstractFilter firstFilter;

//spring注入后自动执行
@PostConstruct
public void initializeChainFilter(){
    //把所有调用的逻辑注入到责任链,按照Order排序,越小优先级越高
    for(int i = 0;i<abstractFilterList.size();i++){
        if(i == 0){
            firstFilter = abstractFilterList.get(i);
        }else{
            firstFilter.getLastFilter().setNextFilter(abstractFilterList.get(i));
        }
    }
}

//直接使用
public Response exec(){
    firstFilter.filter(filterRequest, response);
    return response;
}

使用设计模式的好处

看下使用责任链模式后,有什么好处!

  1. 新增拦截逻辑,只需要再实现一个AbstractFilter类即可
  2. 修改拦截顺序,只需要修改Order注解的大小,越小,优先级越高
  3. 代码清晰,所有处理逻辑下沉到实现类中

使用设计模式的缺点

做到了低耦合,高扩展。但也带来了一些不好的地方

  1. 逻辑更复杂,用了链式等数据结构,要注意单例的问题,不能重复使用
  2. 类数量激增,一个拦截器就一个类

最后小结一下

不是什么地方都适合使用设计模式,如果逻辑简单,你硬要使用设计模式,只会带来结构上的复杂,大家可以按照大家的业务场景来使用。

谁能干掉了if else的更多相关文章

  1. 干掉命令行窗口下MySql乱码

    晚上重温dos窗口操作mysql的时候,遇到了一个巨蛋疼的问题------>中文验证码  -->_-->,所以找了找资料弄懂了怎么解决乱码问题,,小记一下. 新建一个表 create ...

  2. 干掉Unity3D

    我为什么想干掉Unity3D? 这个问题容我不答,每个做技术的人总有一些完美主义. 你使用u3d的过程中是不是痛并快乐着呢. 就从两个国内具有相当普遍性的痛点说起. il2cpp,unity作出了这个 ...

  3. Markdown会干掉Html吗?

    Markdown会干掉Html吗? 很明显,MarkDown正在已一种比病毒还快的速度传播着,量子的机器人语言也是深受其启发,当然了,在这个东西没搞出来之前,MarkDown就能干很多事情,比如在线编 ...

  4. Excel应该这么玩——1、命名单元格:干掉常数

    命名单元格:通过名称来引用单元格中的值,常用于引用固定不变的值. 单元格是Excel中存储数据的最小单位,在公式中通过A1.B2之类的名称来引用其中的值.A1只是单元格的坐标,就好像人的身份证号.生活 ...

  5. 夺命雷公狗---DEDECMS----8dedecms干掉首页和-文档页-栏目页的页面的广告

    我们首先来将首页生成静态页面,如下图所示: 成功后,如下显示: 如果成功后则在文件夹下多了一个index.html的文件.. 我们的首页静态页面是通过模版文件生成,所以我们只需要把模版文件的广告标签删 ...

  6. 干掉cmd:windows下使用linux命令行

    对于喜欢用命令行的朋友们,在windows下面使用cmd窗口是不是很不爽?复制不方便?不能随意放大缩小?如果需要多个控制台要多个窗口?....各种不爽 一.基础工具 如果你也不爽,那就对了,所以给大家 ...

  7. Linux中 干掉原来的PHP方法

    干掉原来的PHP方法: 查看php版本命令:#php -v这个命令是删除不干净的#yum remove php因为使用这个命令以后再用#php -v还是会看到有版本信息的..... 必须强制删除#rp ...

  8. Xcode6为什么干掉pch(Precompile Prefix Header)&如何添加pch文件

    转载:  http://blog.csdn.net/iosdevtip/article/details/40918353 一直在用xcode6开发,但项目都是在xcode5上创建的,所以一直没注意到, ...

  9. Xcode6为什么干掉pch(Precompile Prefix Header)&amp;怎样加入pch文件

    一直在用xcode6开发,但项目都是在xcode5上创建的,所以一直没注意到,xcode6居然干掉pch文件了. 为什么xcode6没有自己主动创建pch文件呢? 简单地看:我们在写项目的时候,大部分 ...

  10. 使用gc、objgraph干掉python内存泄露与循环引用!

    Python使用引用计数和垃圾回收来做内存管理,前面也写过一遍文章<Python内存优化>,介绍了在python中,如何profile内存使用情况,并做出相应的优化.本文介绍两个更致命的问 ...

随机推荐

  1. Mac/Win录屏工具推荐-LICEcap

    轻小.便捷.操作简单 下载 LICEcap v1.30 for macOS LICEcap v1.28 for Windows 参考地址

  2. 如何在centos上配置802.1Q VLAN标记,linux单网卡多vlan多网段Ip配置案例

    介绍 VLAN使将大型网络分成较小且易于管理的网络成为可能.802.1Q是所有供应商都在其网络设备中实施的标准.某些交换机能够将多个VLAN分配给单个网络端口.使用此功能,您可以将多个VLAN分配给单 ...

  3. LinkedList作为栈和队列的使用

    最近在LeekCode用java写一些算法时,经常遇到要使用栈和队列结构,使用栈的话,Stack已经不被推荐使用了,所以栈和队列我们通常都是用LinkedList这种双链表结构实现.Linkedlis ...

  4. 关于ollydbg的堆栈视图的使用(结合crackme2分析)

    在crackme2中我们通过在弹出的窗口处下段然后逐层往用户区回溯,我们利用不断下断点和反复运行程序回溯,其实可以利用Ollydbg的堆栈视图来完成, ollydbg的堆栈视图反映了程序在运行期间函数 ...

  5. [MySQL数据库之记录的详细操作:增、改、删、单表查询、多表查询]

    [MySQL数据库之记录的详细操作:增.改.删.单表查询.多表查询] 记录详细操作 增.删.改 增: insert t1(字段1,字段2,字段3) values (值1,值2,值3), (值1,值2, ...

  6. [DB] Spark SQL

    概述 基于Spark,兼容Hive 集成在Spark中,不需单独安装 提供统一的数据访问方式 结构化的数据类型:JDBC.JSON.Hive.Parquet(Saprk SQL 默认数据源) 支持标准 ...

  7. gparted 当分区空间大于1T 用gparted分区

    lsblkfdisk -lparted -s /dev/sdb mklabel msdos parted -s /dev/sdb mkpart primary 0 100%lsblk dfparted ...

  8. Linux ll查看文件属性详解-软硬链接详解

    Linux文件属性及类型 [root@localhost ~]# ll anaconda-ks.cfg 文件类型 权限 硬连接数 文件的大小 文件的创建,修改时间 - rw-------. 1 roo ...

  9. Linux进阶之Linux破解密码、yum源配置、防火墙设置及源码包安装

    一.老师语录: 所有要求笔试的公司都是垃圾公司 笔试(是考所有的涉及到的点) 要有自己的卖点.专长(给自己个标签)(至少一个) 生产环境中,尽量使用mv(mv到一个没用的目录下),少使用rm 二.防火 ...

  10. shell基础之99乘法表

    方法一: 1 #!/bin/bash 2 for a in {1..9};do 3 for b in {1..9};do 4 c=`echo "$a*$b" |bc` 5 if [ ...