個人BO之數據保護

個人BO
1-個人BO之強類型
2-個人BO之數據保護
3-個人BO之狀態控制
4-個人BO之導航屬性html

數據保護指什麼

軟件的運行離不開數據,數據通常存在對象中。這種對象在 Java 統稱爲 POJO,在 C# 則爲 POCO。若 POJO 的Property(屬性)都是可讀寫的(publicget/set),沒有方法或只有少許的持久化方法,這種稱爲貧血模型。java

貧血模型只存儲數據而對數據沒有控制,對象內部和外部都能修改。業務邏輯通常寫在外部,就算寫在內部也由於 Property 可由外界隨意修改而控制不住數據。從而這個 POJO 只是存儲數據,沒有控制數據的能力,也就沒有保護數據的能力。一個對象相關的邏輯不能被很好地集中管理,而是分散在各個外部方法中。從而產生了幾個不良後果:post

貧血模型缺點多

  1. 不一樣狀況下對同份數據的處理有邏輯矛盾,且不易發現。如一處設屬性值爲-1,另外一處卻沒有考慮值是-1的狀況。
  2. 相同的功能寫多份,修改時容易改漏。常常複製粘貼的代碼後果很可怕。
  3. 軟件的質量不好,容易發生改了一個 Bug 產生兩個 Bug。難以交付。

BO 如何保護數據

BO 中所有的 Property 對外都是隻讀的,外部沒法直接修改 Property。只有 BO 本身內部才能修改屬性,從而保護了數據。外部經過調用 BO 的業務方法修改一個或多個屬性,業務方法可對參數和狀態進行各類判斷,知足條件才修改數據。從而保證任什麼時候候 BO 的數據都是合法的。因爲數據只能在內部修改,因此什麼值表明什麼意思是由 BO 本身決定的,統一決定,而不是由外部分散在各個地方的代碼邏輯決定的,因此有效地保證了數據含義的統一性。this

雖然關於這個 BO 本身的業務都寫到 BO 這個類中了(這裏暫無須考慮經過繼承寫到多個類的狀況),起到了集中控制的效果。但內部不一樣的業務方法也可能有共用的邏輯,這些應該經過重構功能,以達到「一個功能只寫一處」的狀態。一個大功能會包含若干個小功能,這裏的「功能」,是泛指大大小小的任何一個功能。不管是面向對象仍是面向過程,都應該努力作到「一個功能只寫一處」。這是解決軟件靈活性與軟件正確性的惟一比較可取的作法。除非把人看成機器,面對以前大量「複製粘貼再改改」的代碼須要修改時也能絕不遺漏地所有修改。lua

BO 的實例化

BO 被定義爲任什麼時候刻都是有意義的,因此並不能new一個空對象,而後再賦值,數據必須在new時就送來,因此 BO 須要提供一個所有屬性的構造方法。另外爲了持久化方便的考慮,也能夠接收一個 PO,從 PO 獲取各個屬性的值。code

網上購物的訂單示例htm

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方法,若非法則返回nullblog

感謝

感謝 Rayman(QQ:25625607) 在我爲【BO 的屬性該全只讀,經過方法來修改】仍是【能夠部分屬性可寫(public set),並在寫時做業務邏輯】猶豫不定時給我了確定的回答。我認爲這是整個 BO 的關鍵所在。繼承

系列導航

1-個人BO之強類型
2-個人BO之數據保護
3-個人BO之狀態控制
4-個人BO之導航屬性

相關文章
相關標籤/搜索