Вы можете заменить List
на Map
. Затем он может содержать как имена параметров, так и фактические значения. Его можно использовать для копирования текущих свойств объекта, редактирования одного или нескольких из них и передачи его конструктору нового объекта.
Когда у объектов есть методы для запроса их текущего состояния, Вы можете заменить методы stati c конечными шаблонными объектами stati c, сохраняя значения по умолчанию свойств, которые можно запросить с помощью указанного метода.
public class Base {
static final Base TEMPLATE = new Base();
final String name, age;
protected Base() {
name = "no name";
age = null;
}
public Base(String name, String age) {
this.name = name;
this.age = age;
}
public Base(Map<String,String> map) {
name = map.get("name");
age = map.get("age");
}
public Map<String,String> arguments() {
HashMap<String,String> map = new HashMap<>();
map.put("name", name);
map.put("age", age);
return map;
}
}
public class Child extends Base {
static final Child TEMPLATE = new Child();
final String position;
protected Child() {
position = "unspecified";
}
public Child(final String name, final String age, final String position) {
super(name, age);
this.position = position;
}
public Child(Map<String, String> map) {
super(map);
this.position = map.get("position");
}
@Override
public Map<String, String> arguments() {
final Map<String, String> map = super.arguments();
map.put("position", position);
return map;
}
}
Вы можете использовать его как
Map<String, String> values = Child.TEMPLATE.arguments();
UI.editValues(values);
Child ch = new Child(values);
Это приводит к шаблону Builder, поскольку есть причины заменить generi c Map
выделенными классами. Эти классы могут определять свойства с различными типами, а также применять ограничения. Бонусные баллы, если класс может сообщать об ограничениях через интерфейс.
Но для каждого фактического типа требуется специализация типа компоновщика. Там много разных вариаций рисунка. Одно из производных Map
напрямую будет выглядеть так:
public class Base {
public static class Builder {
String name = "no name";
int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = Objects.requireNonNull(name);
}
public int getAge() {
return age;
}
public void setAge(int age) {
if(age < 0) throw new IllegalArgumentException();
this.age = age;
}
}
final String name;
final int age;
public Base(String name, int age) {
if(age < 0) throw new IllegalArgumentException();
this.name = Objects.requireNonNull(name);
this.age = age;
}
public Base(Builder b) {
name = b.name;
age = b.age;
}
public void fill(Builder b) {
b.setName(name);
b.setAge(age);
}
}
public class Child extends Base {
public static class Builder extends Base.Builder {
String position = "unspecified";
public String getPosition() {
return position;
}
public void setPosition(String position) {
this.position = Objects.requireNonNull(position);
}
}
final String position;
public Child(final String name, final int age, final String position) {
super(name, age);
this.position = Objects.requireNonNull(position);
}
public Child(Builder b) {
super(b);
this.position = b.position;
}
public void fill(Builder b) {
super.fill(b);
b.setPosition(position);
}
}
Это можно использовать как
Child.Builder b = new Child.Builder();
UI.editValues(b);
Child c = new Child(b);
Обратите внимание, что эти сборщики следуют шаблону Бина относительно свойства , что очень полезно для универсальных c пользовательских интерфейсов. Конечно, это подразумевает, что пользовательский интерфейс обрабатывает изменяемые объекты, но это также относится к вариантам List
и Map
. Ключевым моментом является то, что состояние компоновщика будет использоваться для построения неизменяемых объектов в нужное время, например, перед передачей их в последующий код обработки.