zoukankan      html  css  js  c++  java
  • 我的BO之数据保护

    我的BO
    1-我的BO之强类型
    2-我的BO之数据保护
    3-我的BO之状态控制
    4-我的BO之导航属性

    数据保护指什么

    软件的运行离不开数据,数据一般存在对象中。这种对象在 Java 统称为 POJO,在 C# 则为 POCO。若 POJO 的Property(属性)都是可读写的(publicget/set),没有方法或只有少量的持久化方法,这种称为贫血模型。

    贫血模型只存储数据而对数据没有控制,对象内部和外部都能修改。业务逻辑一般写在外部,就算写在内部也因为 Property 可由外界随意修改而控制不住数据。从而这个 POJO 只是存储数据,没有控制数据的能力,也就没有保护数据的能力。一个对象相关的逻辑不能被很好地集中管理,而是分散在各个外部方法中。从而产生了几个不良后果:

    贫血模型缺点多

    1. 不同情况下对同份数据的处理有逻辑矛盾,且不易发现。如一处设属性值为-1,另一处却没有考虑值是-1的情况。
    2. 相同的功能写多份,修改时容易改漏。经常复制粘贴的代码后果很可怕。
    3. 软件的质量很差,容易发生改了一个 Bug 产生两个 Bug。难以交付。

    BO 如何保护数据

    BO 中全部的 Property 对外都是只读的,外部无法直接修改 Property。只有 BO 自己内部才能修改属性,从而保护了数据。外部通过调用 BO 的业务方法修改一个或多个属性,业务方法可对参数和状态进行各种判断,满足条件才修改数据。从而保证任何时候 BO 的数据都是合法的。由于数据只能在内部修改,所以什么值代表什么意思是由 BO 自己决定的,统一决定,而不是由外部分散在各个地方的代码逻辑决定的,所以有效地保证了数据含义的统一性。

    虽然关于这个 BO 自己的业务都写到 BO 这个类中了(这里暂无须考虑通过继承写到多个类的情况),起到了集中控制的效果。但内部不同的业务方法也可能有共用的逻辑,这些应该通过重构功能,以达到“一个功能只写一处”的状态。一个大功能会包含若干个小功能,这里的“功能”,是泛指大大小小的任何一个功能。无论是面向对象还是面向过程,都应该努力做到“一个功能只写一处”。这是解决软件灵活性与软件正确性的唯一比较可取的做法。除非把人当作机器,面对之前大量“复制粘贴再改改”的代码需要修改时也能毫不遗漏地全部修改。

    BO 的实例化

    BO 被定义为任何时刻都是有意义的,所以并不能new一个空对象,然后再赋值,数据必须在new时就送来,所以 BO 需要提供一个全部属性的构造方法。另外为了持久化方便的考虑,也可以接收一个 PO,从 PO 获取各个属性的值。

    网上购物的订单示例

    public class OrderBo extends BoBase {
        Order order;
        @Autowired
        OrderDB orderDB;
    
        public OrderBo(Order order) {  /* 传入 PO */
            if (order == null)
                throw ParameterException.missData("order");
            this.order = order;
        }
    
        public OrderBo(Long buyerId, Long postDistrictId, String postAddress, String postContactPhone, String evaluation,
                Date createTime, OrderStatus status, EvaluateStatus evaluateStatus) {  /* 传入各个 Property */
            Order entity = new Order();
            entity.setBuyerId(buyerId);
            entity.setPostDistrictId(postDistrictId);
            entity.setPostAddress(postAddress);
            entity.setPostContactPhone(postContactPhone);
            entity.setEvaluation(evaluation);
            entity.setCreateTime(createTime);
            entity.setStatus(status.toString());
            entity.setEvaluateStatus(evaluateStatus);
            this.order = entity;
            this.trackState = BoTrackState.Added;
        }
    
        // region 属性
    
        public Long getId() {
            return order.getId();
        }
    
        protected void setId(Long id) {  /* 每个 set 都不是 public */
            order.setId(id);
            setTrackUpdate();    /* 父类方法,后续文章会介绍 */
        }
        // 买家 Id
        public Long getBuyerId() {
            return order.getBuyerId();
        }
    
        protected void setBuyerId(Long buyerId) {
            order.setBuyerId(buyerId);
            setTrackUpdate();
        }
        // 区县 Id
        public Long getPostDistrictId() {
            return order.getPostDistrictId();
        }
    
        protected void setPostDistrictId(Long postDistrictId) {
            order.setPostDistrictId(postDistrictId);
            setTrackUpdate();
        }
        // 详细地址
        public String getPostAddress() {
            return order.getPostAddress();
        }
    
        protected void setPostAddress(String postAddress) {
            order.setPostAddress(postAddress);
            setTrackUpdate();
        }
        // 联系手机
        public String getPostContactPhone() {
            return order.getPostContactPhone();
        }
    
        protected void setPostContactPhone(String postContactPhone) {
            order.setPostContactPhone(postContactPhone);
            setTrackUpdate();
        }
        // 评价内容
        public String getEvaluation() {
            return order.getEvaluation();
        }
    
        protected void setEvaluation(String evaluation) {
            order.setEvaluation(evaluation);
            setTrackUpdate();
        }
        // 下单时间,创建时间
        public Date getCreateTime() {
            return order.getCreateTime();
        }
    
        protected void setCreateTime(Date createTime) {
            order.setCreateTime(createTime);
            setTrackUpdate();
        }
        // 订单状态
        public OrderStatus getStatus() {
            String sStatus = order.getStatus();
            return OrderStatus.valueOf(sStatus);
        }
    
        protected void setStatus(OrderStatus status) {
            String sStatus = status.toString();
            order.setStatus(sStatus);
            setTrackUpdate();
        }
        // 评价状态:未评价,已评价
        public EvaluateStatus getEvaluateStatus() {
            String sStatus = order.getEvaluateStatus();
            return EvaluateStatus.valueOf(sStatus);
        }
    
        protected void setEvaluateStatus(EvaluateStatus evaluateStatus) {
            String sStatus = evaluateStatus.toString();
            order.setEvaluateStatus(sStatus);
            setTrackUpdate();
        }
        // endregion 属性
    
        // region 操作
    
        public void delete() {
            this.setTrackDeleted();
            this.save();
        }
    
        // 评价
        public void evaluat(string evaluation) {
            /* 不是特定的状态不能评价。若有需要,可以阻止内容为(空)的评价 */
            if (this.getEvaluateStatus() != EvaluateStatus.未评价) {
                throw ParameterException.invalidStatus("订单" + this.getEvaluateStatus() + ",不能评价");
            }
    
            /* 修改评价内容,并修改评价状态,而不是内容和状态可以被外部分别调用! */
            this.setEvaluation(evaluation);
            this.setEvaluateStatus(EvaluateStatus.已评价);
            this.save();    /* 父类方法,后续文章会介绍 */
        }
        // endregion 操作
    }
    

    /* */的内容是本文特意加的说明。

    不足之处

    没有对构造时的数据进行合法性验证。解决办法可以在构造时检查,若非法则抛异常。也可以私有化构造方法,并提供public static方法,若非法则返回null

    感谢

    感谢 Rayman(QQ:25625607) 在我为【BO 的属性该全只读,通过方法来修改】还是【可以部分属性可写(public set),并在写时作业务逻辑】举棋不定时给我了肯定的回答。我认为这是整个 BO 的关键所在。

    系列导航

    1-我的BO之强类型
    2-我的BO之数据保护
    3-我的BO之状态控制
    4-我的BO之导航属性

  • 相关阅读:
    C++调用web服务(java事例供参考)
    ASP.NET1.1与2.0如何引入MagicAjax (转载自http://hi.baidu.com/zzticzh)
    爱,在世界末日时
    Why Google Chrome is Multiprocess Architecture
    Chrome
    Code Reuse in Google Chrome
    Google V8 JavaScrit 研究(1)
    第一篇文章
    User Experience
    WPF
  • 原文地址:https://www.cnblogs.com/BillySir/p/10807218.html
Copyright © 2011-2022 走看看