Design patterns
Шаблон Builder
Поиск…
замечания
Отделяет построение сложного объекта от его представления, так что один и тот же процесс построения может создавать различные представления.
- Отделите логику от представления.
- Логика повторного использования для работы с различными наборами данных.
Builder Pattern / C # / Свободный интерфейс
public class Email
{
public string To { get; set; }
public string From { get; set; }
public string Subject { get; set; }
public string Body { get; set; }
}
public class EmailBuilder
{
private readonly Email _email;
public EmailBuilder()
{
_email = new Email();
}
public EmailBuilder To(string address)
{
_email.To = address;
return this;
}
public EmailBuilder From(string address)
{
_email.From = address;
return this;
}
public EmailBuilder Subject(string title)
{
_email.Subject = title;
return this;
}
public EmailBuilder Body(string content)
{
_email.Body = content;
return this;
}
public Email Build()
{
return _email;
}
}
Пример использования:
var emailBuilder = new EmailBuilder();
var email = emailBuilder
.To("[email protected]")
.From("[email protected]")
.Subject("Email subject")
.Body("Email content")
.Build();
Builder Pattern / Java-реализация
Шаблон Builder позволяет вам создать экземпляр класса со многими необязательными переменными легко читаемым способом.
Рассмотрим следующий код:
public class Computer {
public GraphicsCard graphicsCard;
public Monitor[] monitors;
public Processor processor;
public Memory[] ram;
//more class variables here...
Computer(GraphicsCard g, Monitor[] m, Processer p, Memory ram) {
//code omitted for brevity...
}
//class methods omitted...
}
Это все хорошо и хорошо, если все параметры необходимы. Что делать, если есть много других переменных и / или некоторые из них являются необязательными? Вы не хотите создавать большое количество конструкторов с каждой возможной комбинацией требуемых и необязательных параметров, потому что их трудно поддерживать и для разработчиков понимать. Вы также можете не иметь длинный список параметров, в которых многие, возможно, должны быть введены пользователем пользователем как null.
Шаблон Builder создает внутренний класс Builder, который используется для создания только необходимых необязательных переменных. Это делается с помощью методов для каждой необязательной переменной, которые принимают тип переменной как параметр и возвращают объект Builder, чтобы методы могли быть связаны друг с другом. Любые требуемые переменные помещаются в конструктор Builder, так что их нельзя игнорировать.
Builder также включает метод build()
который возвращает объект, в котором он находится, и должен быть вызван в конце цепочки вызовов метода при создании объекта.
Следуя предыдущему примеру, этот код использует шаблон Builder для класса Computer.
public class Computer {
private GraphicsCard graphicsCard;
private Monitor[] monitors;
private Processor processor;
private Memory[] ram;
//more class variables here...
private Computer(Builder builder) {
this.graphicsCard = builder.graphicsCard;
this.monitors = builder.monitors;
this.processor = builder.processor;
this.ram = builder.ram;
}
public GraphicsCard getGraphicsCard() {
return this.graphicsCard;
}
public Monitor[] getMonitors() {
return this.monitors;
}
public Processor getProcessor() {
return this.processor;
}
public Memory[] getRam() {
return this.ram;
}
public static class Builder {
private GraphicsCard graphicsCard;
private Monitor[] monitors;
private Processor processor;
private Memory[] ram;
public Builder(Processor p){
this.processor = p;
}
public Builder graphicsCard(GraphicsCard g) {
this.graphicsCard = g;
return this;
}
public Builder monitors(Monitor[] mg) {
this.monitors = mg;
return this;
}
public Builder ram(Memory[] ram) {
this.ram = ram;
return this;
}
public Computer build() {
return new Computer(this);
}
}
}
Пример использования этого класса:
public class ComputerExample {
public static void main(String[] args) {
Computer headlessComputer = new Computer.Builder(new Processor("Intel-i3"))
.graphicsCard(new GraphicsCard("GTX-960"))
.build();
Computer gamingPC = new Computer.Builder(new Processor("Intel-i7-quadcode"))
.graphicsCard(new GraphicsCard("DX11"))
.monitors(new Monitor[] = {new Monitor("acer-s7"), new Monitor("acer-s7")})
.ram(new Memory[] = {new Memory("2GB"), new Memory("2GB"), new Memory("2GB"), new Memory("2GB")})
.build();
}
}
В этом примере показано, как шаблон-застройщик может обеспечить большую гибкость в создании класса с небольшим усилием. Объект «Компьютер» может быть реализован на основе желаемой конфигурации вызывающих абонентов в удобном для чтения виде с минимальными усилиями.
Шаблон Builder в Java с композицией
Намерение:
Отделить построение сложного объекта от его представления, чтобы тот же процесс построения мог создавать различные представления
Шаблон Builder полезен, когда у вас есть несколько обязательных атрибутов и множество необязательных атрибутов для создания объекта. Чтобы создать объект с различными обязательными и необязательными атрибутами, вам необходимо предоставить сложный конструктор для создания объекта. Шаблон Builder обеспечивает простой пошаговый процесс для создания сложного объекта.
Случай использования в реальной жизни:
Различные пользователи в FaceBook имеют разные атрибуты, которые состоят из обязательного атрибута, такого как имя пользователя и необязательные атрибуты, такие как UserBasicInfo и ContactInfo. Некоторые пользователи просто предоставляют базовую информацию. Некоторые пользователи предоставляют подробную информацию, включая контактную информацию. В отсутствие шаблона Builder вам необходимо предоставить конструктор со всеми обязательными и необязательными параметрами. Но шаблон Builder упрощает процесс построения, предоставляя простой пошаговый процесс для построения сложного объекта.
Подсказки:
- Предоставьте статический вложенный класс строителя.
- Предоставить конструктор для обязательных атрибутов объекта.
- Предоставлять методы setter и getter для необязательных атрибутов объекта.
- Верните один и тот же объект Builder после установки дополнительных атрибутов.
- Предоставить метод build (), который возвращает сложный объект
Фрагмент кода:
import java.util.*;
class UserBasicInfo{
String nickName;
String birthDate;
String gender;
public UserBasicInfo(String name,String date,String gender){
this.nickName = name;
this.birthDate = date;
this.gender = gender;
}
public String toString(){
StringBuilder sb = new StringBuilder();
sb.append("Name:DOB:Gender:").append(nickName).append(":").append(birthDate).append(":").
append(gender);
return sb.toString();
}
}
class ContactInfo{
String eMail;
String mobileHome;
String mobileWork;
public ContactInfo(String mail, String homeNo, String mobileOff){
this.eMail = mail;
this.mobileHome = homeNo;
this.mobileWork = mobileOff;
}
public String toString(){
StringBuilder sb = new StringBuilder();
sb.append("email:mobile(H):mobile(W):").append(eMail).append(":").append(mobileHome).append(":").append(mobileWork);
return sb.toString();
}
}
class FaceBookUser {
String userName;
UserBasicInfo userInfo;
ContactInfo contactInfo;
public FaceBookUser(String uName){
this.userName = uName;
}
public void setUserBasicInfo(UserBasicInfo info){
this.userInfo = info;
}
public void setContactInfo(ContactInfo info){
this.contactInfo = info;
}
public String getUserName(){
return userName;
}
public UserBasicInfo getUserBasicInfo(){
return userInfo;
}
public ContactInfo getContactInfo(){
return contactInfo;
}
public String toString(){
StringBuilder sb = new StringBuilder();
sb.append("|User|").append(userName).append("|UserInfo|").append(userInfo).append("|ContactInfo|").append(contactInfo);
return sb.toString();
}
static class FaceBookUserBuilder{
FaceBookUser user;
public FaceBookUserBuilder(String userName){
this.user = new FaceBookUser(userName);
}
public FaceBookUserBuilder setUserBasicInfo(UserBasicInfo info){
user.setUserBasicInfo(info);
return this;
}
public FaceBookUserBuilder setContactInfo(ContactInfo info){
user.setContactInfo(info);
return this;
}
public FaceBookUser build(){
return user;
}
}
}
public class BuilderPattern{
public static void main(String args[]){
FaceBookUser fbUser1 = new FaceBookUser.FaceBookUserBuilder("Ravindra").build(); // Mandatory parameters
UserBasicInfo info = new UserBasicInfo("sunrise","25-May-1975","M");
// Build User name + Optional Basic Info
FaceBookUser fbUser2 = new FaceBookUser.FaceBookUserBuilder("Ravindra").
setUserBasicInfo(info).build();
// Build User name + Optional Basic Info + Optional Contact Info
ContactInfo cInfo = new ContactInfo("[email protected]","1111111111","2222222222");
FaceBookUser fbUser3 = new FaceBookUser.FaceBookUserBuilder("Ravindra").
setUserBasicInfo(info).
setContactInfo(cInfo).build();
System.out.println("Facebook user 1:"+fbUser1);
System.out.println("Facebook user 2:"+fbUser2);
System.out.println("Facebook user 3:"+fbUser3);
}
}
выход:
Facebook user 1:|User|Ravindra|UserInfo|null|ContactInfo|null
Facebook user 2:|User|Ravindra|UserInfo|Name:DOB:Gender:sunrise:25-May-1975:M|ContactInfo|null
Facebook user 3:|User|Ravindra|UserInfo|Name:DOB:Gender:sunrise:25-May-1975:M|ContactInfo|email:mobile(H):mobile(W):[email protected]:1111111111:2222222222
Объяснение:
FaceBookUser
- сложный объект с атрибутами ниже, используя состав:String userName; UserBasicInfo userInfo; ContactInfo contactInfo;
FaceBookUserBuilder
- это класс статического строителя, который содержит и создаетFaceBookUser
.userName
- это только обязательный параметр для созданияFaceBookUser
FaceBookUserBuilder
создаетFaceBookUser
, устанавливая дополнительные параметры:UserBasicInfo
иContactInfo
Этот пример иллюстрирует три разных FaceBookUsers с различными атрибутами, построенными из Builder.
- fbUser1 был создан как FaceBookUser только с атрибутом userName
- fbUser2 был создан как FaceBookUser с именем пользователя и UserBasicInfo
- fbUser3 был создан как FaceBookUser с именем пользователя, UserBasicInfo и ContactInfo
В приведенном выше примере композиция использовалась вместо дублирования всех атрибутов FaceBookUser в классе Builder.
В созданных шаблонах мы сначала начнем с простого шаблона, такого как FactoryMethod
и перейдем к более гибким и сложным шаблонам, таким как AbstractFactory
и Builder
.
Java / Ломбок
import lombok.Builder;
@Builder
public class Email {
private String to;
private String from;
private String subject;
private String body;
}
Пример использования:
Email.builder().to("[email protected]")
.from("[email protected]")
.subject("Email subject")
.body("Email content")
.build();
Расширенный шаблон Builder с выражением Java Lambda Expression
public class Person {
private final String salutation;
private final String firstName;
private final String middleName;
private final String lastName;
private final String suffix;
private final Address address;
private final boolean isFemale;
private final boolean isEmployed;
private final boolean isHomewOwner;
public Person(String salutation, String firstName, String middleName, String lastName, String suffix, Address address, boolean isFemale, boolean isEmployed, boolean isHomewOwner) {
this.salutation = salutation;
this.firstName = firstName;
this.middleName = middleName;
this.lastName = lastName;
this.suffix = suffix;
this.address = address;
this.isFemale = isFemale;
this.isEmployed = isEmployed;
this.isHomewOwner = isHomewOwner;
}
}
Старый путь
public class PersonBuilder {
private String salutation;
private String firstName;
private String middleName;
private String lastName;
private String suffix;
private Address address;
private boolean isFemale;
private boolean isEmployed;
private boolean isHomewOwner;
public PersonBuilder withSalutation(String salutation) {
this.salutation = salutation;
return this;
}
public PersonBuilder withFirstName(String firstName) {
this.firstName = firstName;
return this;
}
public PersonBuilder withMiddleName(String middleName) {
this.middleName = middleName;
return this;
}
public PersonBuilder withLastName(String lastName) {
this.lastName = lastName;
return this;
}
public PersonBuilder withSuffix(String suffix) {
this.suffix = suffix;
return this;
}
public PersonBuilder withAddress(Address address) {
this.address = address;
return this;
}
public PersonBuilder withIsFemale(boolean isFemale) {
this.isFemale = isFemale;
return this;
}
public PersonBuilder withIsEmployed(boolean isEmployed) {
this.isEmployed = isEmployed;
return this;
}
public PersonBuilder withIsHomewOwner(boolean isHomewOwner) {
this.isHomewOwner = isHomewOwner;
return this;
}
public Person createPerson() {
return new Person(salutation, firstName, middleName, lastName, suffix, address, isFemale, isEmployed, isHomewOwner);
}
Расширенный способ:
public class PersonBuilder {
public String salutation;
public String firstName;
public String middleName;
public String lastName;
public String suffix;
public Address address;
public boolean isFemale;
public boolean isEmployed;
public boolean isHomewOwner;
public PersonBuilder with(
Consumer<PersonBuilder> builderFunction) {
builderFunction.accept(this);
return this;
}
public Person createPerson() {
return new Person(salutation, firstName, middleName,
lastName, suffix, address, isFemale,
isEmployed, isHomewOwner);
}
}
Использование:
Person person = new PersonBuilder()
.with($ -> {
$.salutation = "Mr.";
$.firstName = "John";
$.lastName = "Doe";
$.isFemale = false;
$.isHomewOwner = true;
$.address =
new PersonBuilder.AddressBuilder()
.with($_address -> {
$_address.city = "Pune";
$_address.state = "MH";
$_address.pin = "411001";
}).createAddress();
})
.createPerson();