系統重構之道-經過Builder去除Bean的Set和Get

寫在前面

系統邏輯編寫中,咱們主要經過切割和封裝成一個個的JavaBean來實現的,在建立JavaBean對象咱們主要有三種方案,可是哪一種方案更利於將來系統的擴展和演進呢?咱們來分析下。ide

構造函數方式

構造函數方式主要的表現形式以下:函數

UserInfo userInfo1 = new UserInfo("xxx", 28);
UserInfo xxxxxx = new UserInfo("xxx", "yyy", 28);
UserInfo xxxxxx1 = new UserInfo("xxx", "yyy", 28, 20200560);

構造函數一般須要可伸縮性,也就是參數列表須要重載。有些時候我不得不傳入null進行初始化。ui

// 不合理的構造使用示範
UserInfo xxxxxx = new UserInfo(null, null, 28);

並且不能直觀看出這些參數所表明的的含義,這有可能引起致命的錯誤,咱們將同類型的username和address互換位置依然成功初始化了對象,不會顯式的引起構建錯誤,這是不合理的。this

另外若是參數列表比較長,有七八個的話,代碼是很是冗長的。設計

JavaBean方式

這種方式是最經常使用的建立對象的方法。只須要使用無參構造函數,而後爲每一個成員變量設置setter方法。code

UserInfo userInfo = new UserInfo();

userInfo.setUsername("xxx");
userInfo.setAge(28);

這種方式很是廣泛,可是存在一個很明顯的問題,對於某個Bean咱們能夠在任何場景,任何邊界以外進行set的操做,這樣就顯得很是難以管理了,也不符合咱們領域化設計的思想,咱們應該採用充血模型方式,將可對屬性形成修改的能力收斂起來,而不是讓其能夠採用set的方式隨意訪問。對象

Builder方式

咱們須要在目標對象(這裏是UserInfo)內部建立了一個靜態類,一般簡單地稱爲Builder。Builder聲明瞭一系列方法來設置對象屬性的值,而後將其返回Builder自己,完成全部調用後,咱們調用Builder的無參build方法進行目標對象的初始化。blog

public class UserInfo {
    private String userName;
    private String address;
    private int age;
    private int time;

    // 私有化無參構造函數
    private UserInfo() {

    }

    public static class Builder {
        private String userName;
        private String address;
        private int age;
        private int time;

        public Builder userName(String userName) {
            this.userName = userName;
            return this;
        }

        public Builder address(String address) {
            this.address = address;
            return this;
        }

        public Builder age(int age) {
            this.age = age;
            return this;
        }

        public Builder time(int time) {
            this.time = time;
            return this;
        }

        public UserInfo build() {
            UserInfo info = new UserInfo();
            info.userName = this.userName;
            info.address = this.address;
            info.age = this.age;
            info.time = this.time;

            return info;
        }
    }

    public String getUserName() {
        return userName;
    }

    public String getAddress() {
        return address;
    }

    public int getAge() {
        return age;
    }

    public int getTime() {
        return time;
    }

    @Override
    public String toString() {
        return "UserInfo{" +
                "userName='" + userName + '\'' +
                ", address='" + address + '\'' +
                ", age=" + age +
                ", time=" + time +
                '}';
    }
}

若是採用Lombok,能夠這麼寫:get

@Builder
public class UserInfoBean {
    private String userName;
    private String address;
    private int age;
    private int time;

    public String getUserName() {
        return userName;
    }

    public String getAddress() {
        return address;
    }

    public int getAge() {
        return age;
    }

    public int getTime() {
        return time;
    }

    @Override
    public String toString() {
        return "UserInfoBean{" +
                "userName='" + userName + '\'' +
                ", address='" + address + '\'' +
                ", age=" + age +
                ", time=" + time +
                '}';
    }
}

而後初始化對象就能夠這麼寫:class

public class Test {

    public static void main(String[] args) {
        UserInfo info = new UserInfo.Builder()
                .userName("xxx")
                .address("yyy")
                .age(28)
                .time(20200560)
                .build();

        System.out.println("info = [" + info + "]");
        System.out.println("info.userName = [" + info.getUserName() + "]");

        UserInfoBean bean = UserInfoBean.builder()
                .userName("xxx")
                .build();

        System.out.println("bean = [" + bean + "]");
        System.out.println("info.address = [" + info.getAddress() + "]");
    }
}

這種方式是我最喜歡的一種方式,特別是當Bean自己具備更加複雜的業務的時候,經過這種方式能夠實現更加的收斂,不是經過屬性的直接get和set,而是採用充血模型方式,以func的方式進行能力訪問。

相關文章
相關標籤/搜索