Переход от JavaBeans к шаблону Builder

Я использую Retrofit в своем приложении, у меня есть классы POJO, которые я использую, чтобы сделать запрос и проанализировать ответ. В настоящее время я использую шаблон JavaBeans и имею методы получения и установки для всех переменных в классе для всех классов POJO.

Вот мой класс пользователя, например

public class User {
    @SerializedName("user_name")
    private String userName;
    @SerializedName("password")
    private String userPassword;
    @SerializedName("address_info")
    private AddressInfo AddressInfo;
    @SerializedName("contact_info")
    private ContactInfo ContactInfo;

    /* 
      *@return The userName
    */
    public String getUserName() {
        return userName;
    }

    /**
     * @param userName The userName
     */

    public void setUserName(String userName) {
        this.userName = userName;
    }

    /**
     * @return The userPassword
     */

    public String getPassword() {
        return userPassword;
    }

    /**
     * @param userPassword The userPassword
     */

    public void setPassword(String userPassword) {
        this.userPassword = userPassword;
    }
    /// so on for the AddressInfo and ContactInfo
}

Это работает хорошо. Я пытаюсь использовать шаблон компоновщика вместо шаблона JavaBeans.

Я изменил свой класс пользователя на:

public class User {
    @SerializedName("user_name")
    private String userName;
    @SerializedName("password")
    private String userPassword;
    @SerializedName("address_info")
    private AddressInfo AddressInfo;
    @SerializedName("contact_info")
    private ContactInfo ContactInfo;


    public static class UserBuilder {

        private String userName;
        private String userPassword;
        private AddressInfo AddressInfo;
        private ContactInfo ContactInfo;

        //builder methods for setting property
        public UserBuilder userName(String user_name) {
            this.userName = user_name;
            return this;
        }

        public UserBuilder userPassword(String user_password) {
            this.userPassword = user_password;
            return this;
        }

        public UserBuilder AddressInfo(AddressInfo addressInfo) {
            this.AddressInfo = addressInfo;
            return this;
        }

        public UserBuilder ContactInfo(ContactInfo contactInfo) {
            this.ContactInfo = contactInfo;
            return this;
        }

        //return fully build object
        public User build() {
            return new User(this);
        }
    }

    //private constructor to enforce object creation through builder

    private User(UserBuilder builder) {
        this.userName = builder.userName;
        this.userPassword = builder.userPassword;
        this.AddressInfo = builder.AddressInfo;
        this.ContactInfo = builder.ContactInfo;
    }

//Getters for userName,userPassword,AddressInfo and ContactInfo
}

Класс AddressInfo

public class AddressInfo {
    @SerializedName("address_1")
    private String address1;
    @SerializedName("city")
    private String city;
    @SerializedName("state")
    private String state;
    @SerializedName("zip_code")
    private String zipCode;

    /**
     * @return The address1
     */
    public String getAddress1() {
        return address1;
    }

    /**
     * @return The city
     */
    public String getCity() {
        return city;
    }

    /**
     * @return The state
     */
    public String getState() {
        return state;
    }

    /**
     * @return The zip code
     */
    public String getZipCode() {
        return zipCode;
    }
}

Вопрос: 1. Я удалил сеттеры из классов POJO AddressInfo и ContactInfo. Нужно ли реализовывать шаблон построителя в классах AddressInfo и ContactInfo? Вот как работает шаблон.

  1. Как я могу добиться этого:

      User user = new User.UserBuilder().userName("test").userPassword("******").address("100 Townsend St").city("San Francisco").zip("94107").build();
    

2 ответа

Решение

С

User user = new User.UserBuilder().userName("test")
    .userPassword("******").address("100 Townsend St")
    .city("San Francisco").zip("94107").build();

Вы будете смешивать вещи. UserBuildr должен нести ответственность за создание пользователя с использованием его адреса / контактной информации, а не за его создание. Вы должны иметь геттеры и сеттеры для экземпляров AddressInfo а также ContactInfo в User класс, а также есть методы для их установки в UserBuilder, Создайте строителя для каждого из них и используйте их следующим образом.

User user = new User.UserBuilder().userName("test")
    .userPassword("******").addressInfo.(new AdressInfo.Builder()
        .address1("100 Townsend St")
        .city("San Francisco").zip("94107").build()).build();

Сделать то же самое для ContactInfo,

Если вы не хотите, чтобы сеттеры AddressInfo а также ContactInfo чтобы быть доступным извне, вы можете сделать их защищенными, строитель все равно сможет получить к ним доступ, поскольку это внутренний класс.

  1. Вы можете реализовать его для всех ваших классов, включая AddressInfo и ContactInfo. Идея этого шаблона - получить контроль над процессом создания объектов и избежать ситуаций, когда ваши объекты могут существовать в неправильном состоянии (например, пользователи без имени и фамилии). Это можно сделать, добавив этап проверки перед созданием объекта.

  2. Вы можете реализовать это так, как показано ниже:

    static class Inner {
    
        String innerValue;
    
        static class Builder {
            String innerValue;
    
            Builder innerVal(final String innerValue) {
                this.innerValue = innerValue;
                return this;
            }
    
            Inner build() {
                Inner inner = new Inner();
                inner.innerValue = this.innerValue;
                return  inner;
            }
        }
    }
    
    static class Outer {
    
    String outerValue;
    
    Inner inner;
    
    static class Builder {
    
        Inner.Builder innerBuilder;
    
        String outerValue;
    
        Builder() {
            this.innerBuilder = new Inner.Builder();
        }
    
        Builder outerVal(final String outerValue) {
            this.outerValue = outerValue;
            return this;
        }
    
        Builder innerVal(final String innerValue) {
            this.innerBuilder.innerVal(innerValue);
            return this;
        }
    
        Outer build() {
            Outer outer = new Outer();
            outer.outerValue = this.outerValue;
            outer.inner = this.innerBuilder.build();
            return  outer;
        }
    }
    }
    

Использование:

    final Outer outer = (new Outer.Builder())
            .innerVal("innerValue")
            .outerVal("outerValue")
            .build();

Но лично я пытаюсь разделить строителей на разные классы, так как это упрощает дизайн.

Другие вопросы по тегам