Design patterns
Builder mönster
Sök…
Anmärkningar
Separerar konstruktionen av ett komplex objekt från dess representation så att samma konstruktionsprocess kan skapa olika representationer.
- Separera logiken från representation.
- Återanvänd logik för att arbeta med olika uppsättningar av data.
Byggmönster / C # / flytande gränssnitt
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;
}
}
Exempel på användning:
var emailBuilder = new EmailBuilder();
var email = emailBuilder
.To("[email protected]")
.From("[email protected]")
.Subject("Email subject")
.Body("Email content")
.Build();
Byggmönster / Java-implementering
Med Builder-mönstret kan du skapa en instans av en klass med många valfria variabler på ett lättläst sätt.
Tänk på följande 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...
}
Allt är bra och bra om alla parametrar är nödvändiga. Tänk om det finns mycket fler variabler och / eller några av dem är valfria? Du vill inte skapa ett stort antal konstruktörer med varje möjlig kombination av nödvändiga och valfria parametrar eftersom det blir svårt att underhålla och för utvecklare att förstå. Du kanske inte vill ha en lång lista med parametrar där många kan behöva anges som null av användaren.
Builder-mönstret skapar en inre klass som kallas Builder som används för att instansera endast de önskade valfria variablerna. Detta görs genom metoder för varje valfri variabel som tar variabeltypen som en parameter och returnerar ett Builder-objekt så att metoderna kan kedjas med varandra. Eventuella erforderliga variabler läggs in i Builder-konstruktören så att de inte kan utelämnas.
Byggmästaren inkluderar också en metod som heter build()
som returnerar objektet som det är i och måste anropas i slutet av kedjan av metodsamtal när objektet byggs.
Följande från föregående exempel använder den här koden Builder-mönstret för datorklassen.
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);
}
}
}
Ett exempel på hur den här klassen skulle användas:
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();
}
}
Detta exempel visar hur byggmönstret kan tillåta mycket flexibilitet i hur en klass skapas med ganska liten ansträngning. Datorobjektet kan implementeras baserat på den önskade konfiguratören på ett lättläst sätt med liten ansträngning.
Byggmönster i Java med sammansättning
Avsikt:
Separera konstruktionen av ett komplext objekt från dess representation så att samma konstruktionsprocess kan skapa olika representationer
Byggmönster är användbart när du har få obligatoriska attribut och många valfria attribut för att konstruera ett objekt. För att skapa ett objekt med olika obligatoriska och valfria attribut måste du tillhandahålla komplex konstruktör för att skapa objektet. Byggmönster ger en enkel steg-för-steg-process för att konstruera ett komplext objekt.
Verkligt användningsfall:
Olika användare i FaceBook har olika attribut, som består av obligatoriska attribut som användarnamn och valfria attribut som UserBasicInfo och ContactInfo. Vissa användare ger helt enkelt grundläggande information. Vissa användare ger detaljerad information inklusive kontaktinformation. I avsaknad av byggmönster måste du tillhandahålla en konstruktör med alla obligatoriska och valfria parametrar. Men Builder-mönstret förenklar byggprocessen genom att tillhandahålla en enkel steg-för-steg-process för att konstruera det komplexa objektet.
tips:
- Ge en statisk kapslad byggmästarklass.
- Tillhandahålla konstruktör för obligatoriska attribut för objekt.
- Tillhandahåller setter- och getter-metoder för valfria attribut för objekt.
- Returnera samma Builder-objekt efter att ha ställt in valfria attribut.
- Ge metoden build () som returnerar komplexa objekt
Kodavsnitt:
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);
}
}
produktion:
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
Förklaring:
FaceBookUser
är ett komplext objekt med nedanstående attribut med komposition:String userName; UserBasicInfo userInfo; ContactInfo contactInfo;
FaceBookUserBuilder
är en statiskFaceBookUserBuilder
som innehåller och byggerFaceBookUser
.userName
är endast obligatorisk parameter för att skapaFaceBookUser
FaceBookUserBuilder
byggerFaceBookUser
genom att ställa in valfria parametrar:UserBasicInfo
ochContactInfo
Detta exempel illustrerar tre olika FaceBookUsers med olika attribut, byggda från Builder.
- fbUser1 byggdes endast som FaceBookUser med attribut för användarnamn
- fbUser2 byggdes som FaceBookUser med användarnamn och UserBasicInfo
- fbUser3 byggdes som FaceBookUser med användarnamn, UserBasicInfo och ContactInfo
I exemplet ovan har kompositionen använts istället för att duplicera alla attribut för FaceBookUser i Builder-klassen.
I skapningsmönster börjar vi först med enkla mönster som FactoryMethod
och gå mot mer flexibla och komplexa mönster som AbstractFactory
och Builder
.
Java / Lombok
import lombok.Builder;
@Builder
public class Email {
private String to;
private String from;
private String subject;
private String body;
}
Exempel på användning:
Email.builder().to("[email protected]")
.from("[email protected]")
.subject("Email subject")
.body("Email content")
.build();
Avancerat byggmönster med Java 8 Lambda-uttryck
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;
}
}
Gammalt sätt
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);
}
Avancerat sätt:
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);
}
}
Användande:
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();