对象存在性检测集中管理

       在中大型业务系统中, 常常需要从数据库中查询某个实体对象。 在进行处理之前, 必须先检测该实体是否存在,以增强系统的健壮性。 不过, 检测代码充斥在主业务流程中又会大大降低业务逻辑的清晰性, 最好集中起来进行管理。 因此,编写了一个类来做这个事情, 只需要一行调用就可以完成相应实体对象的检测。

       美中不足的一点是, 打 log 的位置发生变化了。由于打 log 的主要目标是为了便于调试和定位错误位置, 为了补偿, 一种办法是调用方法时根据具体语境传入自定义的错误消息, 根据错误消息可以定位错误位置; 另一种办法是, 如果不希望每次调用都使用不同的自定义错误消息, 使用 log.error(bizEx.getMessage(), bizEx) 打印异常栈信息, 也可以获取到抛出错误的位置。代码如下(可运行):

       使用方法:

package patterns.singleton.demo;

import junit.framework.Assert;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import patterns.singleton.demo.exception.BizException;
import patterns.singleton.demo.exception.IErrorCode;
import patterns.singleton.demo.exception.NotExistErrorCode;
import patterns.singleton.demo.exception.ResultSet;
import patterns.singleton.demo.model.Order;
import patterns.singleton.demo.model.Product;
import patterns.singleton.demo.CheckEntityExistManager.EntityChecker;
import static patterns.singleton.demo.CheckEntityExistManager.checkEntity;

public class EntityExistCheckTester {
    
    private static final Log log = LogFactory.getLog(EntityExistCheckTester.class);
    
    public static void main(String[] args) throws BizException {
        ResultSet result = demo();
        Assert.assertEquals(NotExistErrorCode.ERROR_ORDER_NOT_EXIST.getCode(), result.getCode());
        Assert.assertEquals(NotExistErrorCode.ERROR_ORDER_NOT_EXIST.getMsg(), result.getMsg());
        
        ResultSet res2 = demo2();
        Assert.assertEquals(IErrorCode.SUCCESSFUL.getCode(), res2.getCode());
        Assert.assertEquals(IErrorCode.SUCCESSFUL.getMsg(), res2.getMsg());
    }
    
    public static ResultSet demo() {
        
        try {
            // Not Need type casting 
            Order order = checkEntity(EntityChecker.ORDER_ID_CHECK, "123", "user-defined msg: order not exist when creating");
            System.out.println(order);
            return new ResultSet(IErrorCode.SUCCESSFUL);
        } catch (BizException bizEx) {
            log.error(bizEx.getMessage(), bizEx);
            return new ResultSet(bizEx.getErrorCode());
        } catch (Exception ex) {
            log.error(ex);
            return new ResultSet(IErrorCode.FAILED);
        }
    }
    
    public static ResultSet demo2() {
        try {
            Product p = checkEntity(EntityChecker.PRODUCT_NAME_CHECK, "God");
            System.out.println(p);
            return new ResultSet(IErrorCode.SUCCESSFUL);
        } catch (BizException bizEx) {
            log.error(bizEx.getMessage(), bizEx);
            return new ResultSet(bizEx.getErrorCode());
        } catch (Exception ex) {
            log.error(ex);
            return new ResultSet(IErrorCode.FAILED);
        }
    }

}

实体存在性集中检测类: CheckEntityExistManager:
package patterns.singleton.demo;

import java.util.HashMap;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import patterns.singleton.demo.exception.BizException;
import patterns.singleton.demo.exception.IErrorCode;
import patterns.singleton.demo.exception.NotExistErrorCode;
import patterns.singleton.demo.model.Order;
import patterns.singleton.demo.model.Product;



public class CheckEntityExistManager {
    
    private static final Log log = LogFactory.getLog(CheckEntityExistManager.class);
    
    private static CheckEntityExistManager checkEntityMgr = getInstance();
    
    private CheckEntityExistManager() {
    }
    
    private static CheckEntityExistManager getInstance() {
        if (checkEntityMgr == null) {
            checkEntityMgr = new CheckEntityExistManager();
        }
        return checkEntityMgr;
    }
    
    interface ICheckEntityExist<T> {
        T checkEntityExist(String entityValue, String msg) throws BizException;
    }
    
    private static ICheckEntityExist<Order> orderIdChecker = checkEntityMgr.new CheckOrderExist();
    private static ICheckEntityExist<Product> productChecker = checkEntityMgr.new CheckProductExist();
    
    public enum EntityChecker {
        ORDER_ID_CHECK(orderIdChecker, NotExistErrorCode.ERROR_ORDER_NOT_EXIST),
        PRODUCT_NAME_CHECK(productChecker, NotExistErrorCode.ERROR_PRODUCT_NOT_EXIST);
        
        EntityChecker(ICheckEntityExist<?> entityChecker, IErrorCode errorCode) {
            this.entityChecker = entityChecker;
            this.errorCode = errorCode;
        }
        
        private static Map<String, IErrorCode> errorMap = new HashMap<String, IErrorCode>();
        
        static {
            for (EntityChecker entityChecker: EntityChecker.values()) {
                ICheckEntityExist<?> checker = entityChecker.getEntityChecker();
                errorMap.put(checker.getClass().getSimpleName(), entityChecker.getErrorCode());
            }
        }
        
        private static IErrorCode getErrorCode(String checkClassSimpleName) {
            return errorMap.get(checkClassSimpleName);
        }
        
        
        private ICheckEntityExist<?> entityChecker;
        private IErrorCode errorCode;
        
        public ICheckEntityExist<?> getEntityChecker() {
            return entityChecker;
        }
        public void setEntityChecker(ICheckEntityExist<?> entityChecker) {
            this.entityChecker = entityChecker;
        }

        public IErrorCode getErrorCode() {
            return errorCode;
        }

        public void setErrorCode(IErrorCode errorCode) {
            this.errorCode = errorCode;
        }
        
        
    }
    
    // may using spring bean autowired in actual projects
    private OrderService orderService = new OrderService() {

        public Order queryOrderByOrderId(int orderId) {
            return null;
        }
        
    };
    
    private ProductService productService = new ProductService() {

        public Product queryProductByName(String productName) {
            Product p = new Product();
            p.setProductId(1);
            p.setName("God");
            p.setDesc("Aman");
            return p;
        }
        
    };
    
    
    class CheckOrderExist implements ICheckEntityExist<Order> {
        
        public Order checkEntityExist(String orderId, String msg) throws BizException {
            IErrorCode errorCode = EntityChecker.getErrorCode(CheckOrderExist.class.getSimpleName());
            String message = (msg == null ? errorCode.getMsg() : msg);
            Order order = orderService.queryOrderByOrderId(Integer.parseInt(orderId));
            return CheckEntityExistManager.throwexOrReturn(order, message, errorCode);
        }
        
    }
    
    class CheckProductExist implements ICheckEntityExist<Product> {

        public Product checkEntityExist(String productName, String msg) throws BizException {
            IErrorCode errorCode = EntityChecker.getErrorCode(CheckProductExist.class.getSimpleName());
            String message = (msg == null ? errorCode.getMsg() : msg);
            Product p = productService.queryProductByName(productName);
            return CheckEntityExistManager.throwexOrReturn(p, message, errorCode);
        }
        
    }
    
    public static <T> T throwexOrReturn(T entity, String message, IErrorCode errorCode) 
                                                        throws BizException {
        if (entity == null) {
            log.error(message);
            throw new BizException(errorCode);
        }
        return entity;
    }
    
    public static <T> T checkEntity(EntityChecker entityChecker, String entityValue, String customMsg) throws BizException {
        ICheckEntityExist<T> checker = (ICheckEntityExist<T>) entityChecker.getEntityChecker();
        return checker.checkEntityExist(entityValue, customMsg);
        
    }
    
    public static <T> T checkEntity(EntityChecker entityChecker, String entityValue) throws BizException {
        ICheckEntityExist<T> checker = (ICheckEntityExist<T>) entityChecker.getEntityChecker();
        return checker.checkEntityExist(entityValue, null);
    }
    
}

interface OrderService {
    Order queryOrderByOrderId(int orderId);
}

interface ProductService {
    Product queryProductByName(String productName);
}

 异常、错误代码相关的类:

package patterns.singleton.demo.exception;


public class BizException extends RuntimeException {
    
    private int code;
    private String msg;
    
    private IErrorCode errorCode;
    
    public BizException(String msg) {
        super(msg);
    }
    
    public BizException(IErrorCode error) {
        this.errorCode = error;
        this.code = error.getCode();
        this.msg = error.getMsg();
    }
    
    public BizException(Throwable cause) {
        super(cause);
    }

    public IErrorCode getErrorCode() {
        return errorCode;
    }
    
}
package patterns.singleton.demo.exception;

public interface IErrorCode {
    
    int getCode();
    String getMsg();
    
    public IErrorCode SUCCESSFUL = new IErrorCode() {
        public int getCode() {
            return 200;
        }
        public String getMsg() {
            return "successful";
        }
    };
    
    public IErrorCode FAILED = new IErrorCode() {
        public int getCode() {
            return 0;
        }
        public String getMsg() {
            return "failed";
        }
    };

}
package patterns.singleton.demo.exception;


public enum NotExistErrorCode implements IErrorCode {
    
    ERROR_ORDER_NOT_EXIST(-180, "order not exist"),
    ERROR_PRODUCT_NOT_EXIST(-190, "product not exist");

    private int code;
    private String msg;
    
    NotExistErrorCode(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }
    
    public int getCode() {
        return this.code;
    }

    public String getMsg() {
        return this.msg;
    }

}
package patterns.singleton.demo.exception;

public class ResultSet<T> {

    public static final ResultSet SUCCESS = new ResultSet();
    
    private int code;
    private String msg;
    
    private T data;
    
    public ResultSet() {
        this.code = 200;
        this.msg = "success";
    }
    
    public ResultSet(T data) {
        this();
        this.data = data;
    }
    
    public ResultSet(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }
    
    public ResultSet(IErrorCode ex) {
        this(ex.getCode(), ex.getMsg());
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
    
}

      数据对象:

      

package patterns.singleton.demo.model;

public class Order {
    
    private Integer orderId;
    private String productName;
    private int    account;
    
    public Integer getOrderId() {
        return orderId;
    }
    public void setOrderId(Integer orderId) {
        this.orderId = orderId;
    }
    public String getProductName() {
        return productName;
    }
    public void setProductName(String productName) {
        this.productName = productName;
    }
    public int getAccount() {
        return account;
    }
    public void setAccount(int account) {
        this.account = account;
    }

}
package patterns.singleton.demo.model;

public class Product {

    private Integer productId;
    private String name;
    private String desc;
    
    public Integer getProductId() {
        return productId;
    }
    public void setProductId(Integer productId) {
        this.productId = productId;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getDesc() {
        return desc;
    }
    public void setDesc(String desc) {
        this.desc = desc;
    }
    
}