Design patterns
Bouwer patroon
Zoeken…
Opmerkingen
Scheidt de constructie van een complex object van de weergave ervan, zodat hetzelfde constructieproces verschillende weergaven kan creëren.
- Scheid de logica van de weergave.
- Hergebruik logica om met verschillende gegevens te werken.
Bouwerpatroon / C # / Vloeiend interface
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;
}
}
Gebruiksvoorbeeld:
var emailBuilder = new EmailBuilder();
var email = emailBuilder
.To("[email protected]")
.From("[email protected]")
.Subject("Email subject")
.Body("Email content")
.Build();
Bouwerpatroon / Java-implementatie
Met het Builder-patroon kunt u op een gemakkelijk leesbare manier een instantie van een klasse maken met veel optionele variabelen.
Overweeg de volgende code:
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...
}
Dit is allemaal goed en goed als alle parameters nodig zijn. Wat als er veel meer variabelen zijn en / of sommige optioneel zijn? U wilt geen groot aantal constructeurs maken met elke mogelijke combinatie van vereiste en optionele parameters, omdat het moeilijk te onderhouden en voor ontwikkelaars wordt om te begrijpen. Misschien wilt u ook geen lange lijst met parameters hebben waarin de gebruiker er mogelijk veel als nul moet invoeren.
Het Builder-patroon maakt een binnenklasse genaamd Builder die wordt gebruikt om alleen de gewenste optionele variabelen te instantiëren. Dit wordt gedaan door methoden voor elke optionele variabele, waarbij het variabeletype als parameter wordt gebruikt en een Builder-object wordt geretourneerd, zodat de methoden aan elkaar kunnen worden gekoppeld. Alle vereiste variabelen worden in de Builder-constructor geplaatst zodat ze niet kunnen worden weggelaten.
De Builder bevat ook een methode genaamd build()
die het object retourneert waarin het zich bevindt en moet worden aangeroepen aan het einde van de reeks methodeaanroepen bij het bouwen van het object.
In navolging van het vorige voorbeeld gebruikt deze code het Builder-patroon voor de klasse 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);
}
}
}
Een voorbeeld van hoe deze klasse zou worden gebruikt:
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();
}
}
Dit voorbeeld laat zien hoe het builderpatroon veel flexibiliteit kan bieden in hoe een klasse met vrij weinig moeite wordt gemaakt. Het computerobject kan worden geïmplementeerd op basis van de gewenste configuratie van de beller op een gemakkelijk leesbare manier met weinig moeite.
Bouwerspatroon in Java met samenstelling
intent:
Scheid de constructie van een complex object van de weergave ervan, zodat hetzelfde constructieproces verschillende weergaven kan maken
Bouwpatroon is handig wanneer u weinig verplichte kenmerken en veel optionele kenmerken hebt om een object te construeren. Als u een object met verschillende verplichte en optionele kenmerken wilt maken, moet u een complexe constructor opgeven om het object te maken. Bouwerspatroon biedt een eenvoudig stapsgewijs proces om een complex object te construeren.
Real life use case:
Verschillende gebruikers in FaceBook hebben verschillende attributen, die bestaan uit verplichte attributen zoals gebruikersnaam en optionele attributen zoals UserBasicInfo en ContactInfo. Sommige gebruikers verstrekken eenvoudig basisinformatie. Sommige gebruikers bieden gedetailleerde informatie, waaronder contactgegevens. Bij afwezigheid van Builder-patroon, moet u een constructor voorzien van alle verplichte en optionele parameters. Maar het Builder-patroon vereenvoudigt het bouwproces door een eenvoudig stapsgewijs proces te bieden om het complexe object te construeren.
Tips:
- Zorg voor een statische geneste bouwklasse.
- Lever constructor voor verplichte attributen van object.
- Bied setter- en getter-methoden voor optionele attributen van een object.
- Retourneer hetzelfde Builder-object na het instellen van optionele kenmerken.
- Geef de methode build (), die een complex object retourneert
Codefragment:
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);
}
}
output:
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
Uitleg:
FaceBookUser
is een complex object met onderstaande kenmerken en de volgende compositie:String userName; UserBasicInfo userInfo; ContactInfo contactInfo;
FaceBookUserBuilder
is een statische builderklasse dieFaceBookUser
bevat en bouwt.userName
is alleen verplichte parameter omFaceBookUser
te bouwenFaceBookUserBuilder
bouwtFaceBookUser
door optionele parameters in te stellen:UserBasicInfo
enContactInfo
Dit voorbeeld illustreert drie verschillende FaceBookUsers met verschillende attributen, gebouwd vanuit Builder.
- fbUser1 is gebouwd als FaceBookUser met alleen het kenmerk userName
- fbUser2 werd gebouwd als FaceBookUser met userName en UserBasicInfo
- fbUser3 werd gebouwd als FaceBookUser met userName, UserBasicInfo en ContactInfo
In het bovenstaande voorbeeld is de compositie gebruikt in plaats van alle kenmerken van FaceBookUser in de Builder-klasse te dupliceren.
In creatieve patronen beginnen we eerst met een eenvoudig patroon zoals FactoryMethod
en gaan we over op flexibelere en complexere patronen zoals AbstractFactory
en Builder
.
Java / Lombok
import lombok.Builder;
@Builder
public class Email {
private String to;
private String from;
private String subject;
private String body;
}
Gebruiksvoorbeeld:
Email.builder().to("[email protected]")
.from("[email protected]")
.subject("Email subject")
.body("Email content")
.build();
Geavanceerd bouwpatroon met Java 8 Lambda-expressie
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;
}
}
Oude weg
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);
}
Geavanceerde manier:
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);
}
}
Gebruik:
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();