代码设计 用枚举方式提供和管理异常断言能力,优雅解决代码中的new Exception问题

背景

项目中通过自定义异常类来对异常逻辑进行管理,在逻辑异常时每次如果都通过new的方式创建异常貌似不太优雅;

思路

我们可以考虑通过创建断言工具类来达到这一目标,枚举可以理解成在类里面预先会定义好若干个该类型的对象,这样就可以避免在代码中偏频繁的用new了;

把这个作为出发点,我们可以用枚举来管理异常类的对象, 其原理就是组合模式

自定义异常

这里我们定义两个主要的业务异常类,当然这个自定义异常类根据情况可以再设计

BusinessException
package com.xx.design.exception.base;

/**
 * @author EDY
 */
public class BusinessException extends RuntimeException {

    public BusinessException() {
        super();
    }

    public BusinessException(String message) {
        super(message);
    }

    public BusinessException(String message, Throwable cause) {
        super(message, cause);
    }

    public BusinessException(Throwable cause) {
        super(cause);
    }

    protected BusinessException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }

}

AuthException
package com.xx.design.exception.base;

/**
 * @author EDY
 */
public class AuthException extends RuntimeException {

    public AuthException() {
        super();
    }

    public AuthException(String message) {
        super(message);
    }

    public AuthException(String message, Throwable cause) {
        super(message, cause);
    }

    public AuthException(Throwable cause) {
        super(cause);
    }

    protected AuthException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}

设计断言接口Assert

以上为定义的两个基础异常类,下面我们就来编写我们的异常断言类,首先定义一个断言接口,主要抽象出需要提供的断言方法:

package com.xx.design.exception.ass;

public interface Assert {

    /**
     * 断言对象 obj 非空。如果对象 obj 为空,则抛出异常
     * 异常信息 message 支持传递参数方式,避免在判断之前进行字符串拼接操作
     *
     * @param obj     待判断对象
     * @param message 异常消息
     */
    void assertNotNull(Object obj, String message);

    /**
     *
     * @param obj
     * @param message
     */
    void assertNull(Object obj, String message);

    /**
     * 断言是否为真
     *
     * @param bool    条件
     * @param message 异常消息
     */
    void assertTrue(Boolean bool, String message);
}

设计异常生产者接口ExceptionProvider

然后定一个异常的生产者接口 ExceptionProvider,主要作用是创建异常对象,由于我们的业务异常设计成了RuntimeException的子类,那么我们定义一个生产RuntimeException 的接口

package com.xx.design.exception.ass;

/**
 * @author EDY
 */
public interface ExceptionProvider {

    /**
     * 创建异常
     *
     * @param message 参数
     * @return 异常
     */
    RuntimeException newException(String message);
}

断言模板 AbstractAssert

接下来我们定义一个断言并抛异常的模板类 AbstractAssert,主要是把 Assert和ExceptionProvider组合起来,重写Assert里的方法(抽象出一套模板),然后视情况生产并抛出异常,而其中的生产异常就需要子类来实现了;

package com.xx.design.exception.ass;


import com.xx.design.exception.base.BusinessException;

/**
 * @author EDY
 */
public abstract class AbstractAssert implements Assert, ExceptionProvider {

    /**
     * 断言对象 obj 非空。如果对象 obj 为空,则抛出异常
     * 异常信息 message 支持传递参数方式,避免在判断之前进行字符串拼接操作
     *
     * @param obj     待判断对象
     * @param message message占位符对应的参数列表
     */
    @Override
    public void assertNotNull(Object obj, String message) {
        if (obj == null) {
            throw newException(message);
        }
    }

    /**
     * 断言true
     *
     * @param bool    条件
     * @param message 异常消息
     */
    @Override
    public void assertTrue(Boolean bool, String message) {
        if (!(bool != null && bool)) {
            throw new BusinessException(message);
        }
    }

    /**
     * 断言为null
     *
     * @param obj     待判断对象
     * @param message 异常提示消息
     */
    @Override
    public void assertNull(Object obj, String message) {
        if (obj != null) {
            throw new BusinessException(message);
        }
    }
}

类图如下:
在这里插入图片描述

具体的Assert类

这类型的类主要职责是生产异常,不同的业务异常类可以对应一个Assert类,其继承AbstractAssert并实现 newException方法

BusinessExceptionAssert
package com.xx.design.exception.ass;

import com.xx.design.exception.base.BusinessException;

/**
 * BusinessException 断言工具
 *
 * @author EDY
 */
public class BusinessExceptionAssert extends AbstractAssert {

    /**
     * 生成 BusinessException
     *
     * @param message 异常消息
     * @return BusinessException
     */
    @Override
    public RuntimeException newException(String message) {
        return new BusinessException(message);
    }
}

类图如下
在这里插入图片描述

UnauthorizedExceptionAssert
package com.xx.design.exception.ass;


import com.xx.design.exception.base.AuthException;

/**
 * 授权异常的断言类
 *
 * @author EDY
 */
public class UnauthorizedExceptionAssert extends AbstractAssert {

    /**
     * 生成 UnauthorizedException
     *
     * @param message 异常消息
     * @return BusinessException
     */
    @Override
    public RuntimeException newException(String message) {
        return new AuthException(message);
    }
}


类图如下
在这里插入图片描述

至此,我们在项目中可以直接使用 BusinessExceptionAssert 和 UnauthorizedExceptionAssert 来进行断言了,结合开头说的使用枚举来管理断言类于是我们有了以下的设计:

Assert管理类

我们使用 Asserts(注意单词后面的s,不是Assert) 枚举类管理AbstractAssert 的子类,但Asserts 枚举类也要实现Assert 以便继承Assert 提供的接口;

Asserts的设计核心是内部一个 Assert ass; 属性,结合Asserts其构造方法将AbstractAssert 子类都纳入Asserts管理!

package com.xx.design.exception.ass;


/**
 * @author EDY
 * 所有的异常断言对象,后续可根据异常类中的增加而扩展
 */
public enum Asserts implements Assert {

    /**
     * 业务异常的断言对象
     */
    BUSINESS_ASSERT(new BusinessExceptionAssert()),

    /**
     * 授权异常断言对象
     */
    AUTH_ASSERT(new UnauthorizedExceptionAssert());

    Assert ass;

    Asserts(Assert azz) {
        this.ass = azz;
    }

    @Override
    public void assertNotNull(Object obj, String message) {
        this.ass.assertNotNull(obj, message);
    }

    @Override
    public void assertNull(Object obj, String message) {
        this.ass.assertNull(obj, message);
    }

    @Override
    public void assertTrue(Boolean bool, String message) {
        this.ass.assertTrue(bool, message);
    }
}

代码中的使用
package com.xx.design.exception;

import com.xx.design.exception.ass.Asserts;

/**
 * @author EDY
 */
public class AssertsTest {
    public static void main(String[] args) {
        Object a = new Object();
        Asserts.BUSINESS_ASSERT.assertNull(a, "a应该为null,实际上不为null,断言失败");

    }
}

最终代码结构如下:


在这里插入图片描述


代码可以在: 【gitee】 https://gitee.com/aqu415/code-demo/tree/master/design/src/main/java/com/xx/design下载

over~~

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值