Design patterns
Wzór konstruktora
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:
- Podaj statyczną zagnieżdżoną klasę konstruktora.
- Podaj konstruktor dla obowiązkowych atrybutów obiektu.
- Podaj metody ustawiające i pobierające dla opcjonalnych atrybutów obiektu.
- Zwróć ten sam obiekt Builder po ustawieniu opcjonalnych atrybutów.
- 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:
FaceBookUser
to złożony obiekt z poniższymi atrybutami wykorzystujący kompozycję:String userName; UserBasicInfo userInfo; ContactInfo contactInfo;
FaceBookUserBuilder
to statyczna klasa konstruktorów, która zawiera i budujeFaceBookUser
.userName
jest tylko parametrem obowiązkowym do budowyFaceBookUser
FaceBookUserBuilder
budujeFaceBookUser
ustawiając parametry opcjonalne:UserBasicInfo
iContactInfo
Ten przykład ilustruje trzy różne FaceBookUsers z różnymi atrybutami, zbudowane z Buildera.
- fbUser1 został zbudowany jako FaceBookUser tylko z atrybutem userName
- fbUser2 został zbudowany jako FaceBookUser z userName i UserBasicInfo
- 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();