Szukaj…


Uwagi

Oddziela budowę złożonego obiektu od jego reprezentacji, dzięki czemu ten sam proces budowy może tworzyć różne reprezentacje.

  • Oddziel logikę od reprezentacji.
  • Ponownie użyj logiki do pracy z innym zestawem danych.

Wzorzec konstruktora / C # / Płynny interfejs

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;
    }
}

Przykład użycia:

var emailBuilder = new EmailBuilder();
var email = emailBuilder
    .To("[email protected]")
    .From("[email protected]")
    .Subject("Email subject")
    .Body("Email content")
    .Build();

Wdrożenie wzorca / implementacji Java

Wzorzec konstruktora umożliwia utworzenie instancji klasy z wieloma opcjonalnymi zmiennymi w łatwy do odczytania sposób.

Rozważ następujący kod:

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...

}

Wszystko dobrze i dobrze, jeśli wszystkie parametry są konieczne. Co jeśli jest o wiele więcej zmiennych i / lub niektóre z nich są opcjonalne? Nie chcesz tworzyć dużej liczby konstruktorów z każdą możliwą kombinacją wymaganych i opcjonalnych parametrów, ponieważ staje się trudna do utrzymania i dla programistów do zrozumienia. Być może nie chcesz mieć długiej listy parametrów, w których użytkownik może wymagać wprowadzenia wielu wartości null.

Wzorzec konstruktora tworzy wewnętrzną klasę o nazwie konstruktor, która służy do tworzenia tylko żądanych zmiennych opcjonalnych. Odbywa się to za pomocą metod dla każdej opcjonalnej zmiennej, która przyjmuje typ zmiennej jako parametr i zwraca obiekt Builder, aby metody mogły być ze sobą połączone. Wszelkie wymagane zmienne są umieszczane w konstruktorze Konstruktora, aby nie można było ich pominąć.

Konstruktor zawiera również metodę o nazwie build() która zwraca obiekt, w którym się znajduje, i musi zostać wywołana na końcu łańcucha wywołań metody podczas budowania obiektu.

Zgodnie z poprzednim przykładem ten kod używa wzorca Builder dla klasy 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);
        }
    }
}

Przykład zastosowania tej klasy:

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();
    }

}

Ten przykład pokazuje, w jaki sposób wzorzec konstruktora może pozwolić na dużą elastyczność w tworzeniu klasy przy stosunkowo niewielkim wysiłku. Obiekt Computer można zaimplementować w oparciu o pożądaną konfigurację dzwoniących, w sposób łatwy do odczytania, przy niewielkim wysiłku.

Wzór konstruktora w Javie z kompozycją

Zamiar:

Oddziel konstrukcję złożonego obiektu od jego reprezentacji, aby ten sam proces budowy mógł tworzyć różne reprezentacje

Wzorzec konstruktora jest przydatny, gdy masz niewiele atrybutów obowiązkowych i wiele atrybutów opcjonalnych do zbudowania obiektu. Aby utworzyć obiekt z różnymi obowiązkowymi i opcjonalnymi atrybutami, musisz dostarczyć złożonego konstruktora, aby utworzyć obiekt. Wzorzec budowniczego zapewnia prosty krok po kroku proces tworzenia złożonego obiektu.

Prawdziwy przypadek użycia:

Różni użytkownicy FaceBook mają różne atrybuty, na które składają się atrybuty obowiązkowe, takie jak nazwa użytkownika i atrybuty opcjonalne, takie jak UserBasicInfo i ContactInfo. Niektórzy użytkownicy po prostu podają podstawowe informacje. Niektórzy użytkownicy podają szczegółowe informacje, w tym dane kontaktowe. W przypadku braku wzorca konstruktora musisz dostarczyć konstruktorowi wszystkie obowiązkowe i opcjonalne parametry. Ale wzorzec Konstruktora upraszcza proces budowy, zapewniając prosty proces krok po kroku w celu zbudowania złożonego obiektu.

Wskazówki:

  1. Podaj statyczną zagnieżdżoną klasę konstruktora.
  2. Podaj konstruktor dla obowiązkowych atrybutów obiektu.
  3. Podaj metody ustawiające i pobierające dla opcjonalnych atrybutów obiektu.
  4. Zwróć ten sam obiekt Builder po ustawieniu opcjonalnych atrybutów.
  5. Podaj metodę build (), która zwraca obiekt złożony

Fragment kodu:

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);
    }
}

wynik:

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

Wyjaśnienie:

  1. FaceBookUser to złożony obiekt z poniższymi atrybutami wykorzystujący kompozycję:

    String userName;
    UserBasicInfo userInfo;
    ContactInfo contactInfo;
    
  2. FaceBookUserBuilder to statyczna klasa konstruktorów, która zawiera i buduje FaceBookUser .

  3. userName jest tylko parametrem obowiązkowym do budowy FaceBookUser

  4. FaceBookUserBuilder buduje FaceBookUser ustawiając parametry opcjonalne: UserBasicInfo i ContactInfo

  5. Ten przykład ilustruje trzy różne FaceBookUsers z różnymi atrybutami, zbudowane z Buildera.

    1. fbUser1 został zbudowany jako FaceBookUser tylko z atrybutem userName
    2. fbUser2 został zbudowany jako FaceBookUser z userName i UserBasicInfo
    3. fbUser3 został zbudowany jako FaceBookUser z userName, UserBasicInfo i ContactInfo

W powyższym przykładzie użyto kompozycji zamiast duplikowania wszystkich atrybutów FaceBookUser w klasie Builder.

W szablonach kreacyjnych zaczniemy od prostego wzoru, takiego jak FactoryMethod i przejdziemy do bardziej elastycznych i złożonych wzorów, takich jak AbstractFactory i Builder .

Java / Lombok

import lombok.Builder;

@Builder
public class Email {

    private String to;
    private String from;
    private String subject;
    private String body;

}

Przykład użycia:

Email.builder().to("[email protected]")
        .from("[email protected]")
        .subject("Email subject")
        .body("Email content")
        .build();

Zaawansowany wzorzec konstruktora z wyrażeniem lambda Java 8

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;
 }
}

Stara droga

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);
}

Zaawansowany sposób:

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);
}

}

Stosowanie:

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();

Patrz: https://medium.com/beingprofessional/think-functional-advanced-builder-pattern-using-lambda-284714b85ed5#.d9sryx3g9



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow