2015-11-16 2 views
4

Давайте предположим, что мы имеем User и UserBuilder класса в своем собственном пакете, что мы хотим быть неизменны и в целостном состоянии до инициализации, определяется следующим образом:Является ли этот допустимый вариант шаблона строителя?

public class User { 

private final String firstName, lastName; 
private final int age; 
private final String adress; 
    protected User(UserBuilder buildUser) { //constructor acessible only in same packge 
     this.firstName = buildUser.lastName; 
     this.lastName = buildUser.lastName; 
     this.age = buildUser.age; 
     this.adress = buildUser.adress; 
    } 

    public String getFirstName() { 
    return firstName; 
    } 
    ... // and other getters 
} 

А класс строитель следующим образом:

public class UserBuilder { 

    public final String firstName; 
    public final String lastName; 
    public int age; 
    public String adress; 

    public UserBuilder(String firstName, String lastName) { 
     this.firstName = firstName; 
     this.lastName = lastName; 
    } 

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

    public UserBuilder setAdress(String adress) { 
     this.adress = adress; 
     return this; 
    } 

    public UserBuilder getUser() { 
     return this; 
    } 

    public User build() { 
     return new User(getUser()); 
    } 
} 

И, наконец, мы строим пользователю в классе, который находится в другом пакете:

public static void main(String[] args) { 
     User user = new UserBuilder("John","Doe") 
       .setAge(22) 
       .build(); 
     // User user = new User(UserBuilder) //error protected constructor     
    } 

Это считается безопасным и хорошим дизайном? Если нет, то почему?

ответ

0

Вы извлекаете объект, который может быть изменен, так что это правильно. Но вы создаете объект User, осведомленный о объекте builder, и я думаю, что это неправильно, потому что класс User не должен знать, что существует класс строителя, вы связываете два класса, я имею в виду, что пользователь напрямую зависит от UserBuilder без UserBuilder Пользователь не может скомпилировать и это не хороший дизайн

Я думаю, что вы бы лучше дизайн, следуя еще ответы на вопросы, с теми примерами, которые будут удалены классы соединения

0
  1. Место UserBuilder внутри пользователя

  2. Создать конструктор пользователя, первый/фамилия, имя, адрес, возраст

  3. Сделать конструктор Личные

+0

Я хотел избежать вложенного строителя, потому что я считаю, что ухудшает читаемость кода. Я знаю, если у вас есть вложенный конструктор, вы можете иметь частный конструктор. –

+1

Затем выберите видимость конструктора по умолчанию, не защищенную – Nyavro

+0

Но тогда вы можете передать UserBuilder внутри конструктора User в несогласованном состоянии, вызвав конструктор пользователя и используя экземпляр UserBuilder, который может быть или не быть полностью инициализирован, что делает все упражнение с Builder бессмысленно. –

0

защищаемого не доступен ТОЛЬКО в том же пакете, но и в суб-классов. Включите класс Builder как вложенный класс в User. Этот подход описан here.

1

Мои предложения:

  • Поместите Builder внутри User, поэтому она является более тривиальным, что Builder строит и пользователь может получить доступ к частным полям Builder, поэтому нет геттер необходимости в строитель.
  • Сделать User конструктором private, потому что protected означает, что производные классы могут получить доступ к конструктору, поэтому неизменность может сломаться.
  • getUser() метод не нужен.

Вот мой пример:

public final class User { 

    private final String firstName, lastName; 
    private final int age; 
    private final String address; 
    private final List<User> friends; 

    private User(Builder builder) { 
     this.firstName = builder.lastName; 
     this.lastName = builder.lastName; 
     this.age = builder.age; 
     this.address = builder.address; 
     this.friends = Collections.unmodifiableList(new ArrayList<>(builder.friends)); //immutable list 
    } 

    public String getFirstName() { 
     return firstName; 
    } 

    public List<User> getFriends() { 
     return friends; 
    } 

    /** 
    * other getters; 
    */ 

    public static class Builder { 
     private String firstName, lastName; 
     private int age; 
     private String address; 
     private List<User> friends = new ArrayList<>(); 

     public Builder(String firstName, String lastName) { 
      this.firstName = firstName; 
      this.lastName = lastName; 
     } 

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

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

     public Builder addFriend(User friend) { 
      this.friends.add(friend); 
      return this; 
     } 

     public User build() { 
      return new User(Builder.this); 
     } 
    } 

    public static void main(String[] args) { 
     User johnSmith = new User.Builder("John", "Smith").setAge(33).setAddress("New York").build(); 
    } 

} 
+1

Также классы в одном пакете могут получить доступ к элементам 'protected'. См. Https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html. –

Смежные вопросы