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