Design patterns
Motif de constructeur
Recherche…
Remarques
Séparer la construction d'un objet complexe de sa représentation afin qu'un même processus de construction puisse créer différentes représentations.
- Séparer la logique de la représentation.
- Réutiliser la logique pour travailler avec différents ensembles de données.
Modèle de générateur / C # / Interface fluide
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;
}
}
Exemple d'utilisation:
var emailBuilder = new EmailBuilder();
var email = emailBuilder
.To("[email protected]")
.From("[email protected]")
.Subject("Email subject")
.Body("Email content")
.Build();
Modèle de générateur / Implémentation Java
Le modèle Builder vous permet de créer une instance d'une classe avec de nombreuses variables facultatives d'une manière facile à lire.
Considérez le code suivant:
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...
}
Tout va bien si tous les paramètres sont nécessaires. Et s'il y a beaucoup plus de variables et / ou certaines d'entre elles sont facultatives? Vous ne voulez pas créer un grand nombre de constructeurs avec chaque combinaison possible de paramètres obligatoires et facultatifs, car cela devient difficile à gérer et à comprendre pour les développeurs. Il se peut également que vous ne souhaitiez pas avoir une longue liste de paramètres dans lesquels l'utilisateur peut avoir à saisir beaucoup de paramètres nuls.
Le modèle de générateur crée une classe interne appelée Builder qui permet d'instancier uniquement les variables facultatives souhaitées. Cela se fait par des méthodes pour chaque variable facultative qui prend le type de variable comme paramètre et renvoie un objet Builder afin que les méthodes puissent être chaînées les unes avec les autres. Toutes les variables requises sont placées dans le constructeur Builder afin qu'elles ne puissent pas être omises.
Le générateur inclut également une méthode appelée build()
qui renvoie l'objet dans lequel elle se trouve et doit être appelée à la fin de la chaîne d'appels de méthode lors de la construction de l'objet.
À la suite de l'exemple précédent, ce code utilise le modèle Builder pour la classe 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);
}
}
}
Un exemple d'utilisation de cette classe:
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();
}
}
Cet exemple montre comment le modèle de générateur peut permettre une grande flexibilité dans la création d'une classe avec un effort assez réduit. L'objet Ordinateur peut être implémenté en fonction de la configuration souhaitée par les appelants dans un format facile à lire et sans effort.
Modèle de constructeur en Java avec composition
Intention:
Séparer la construction d'un objet complexe de sa représentation afin qu'un même processus de construction puisse créer différentes représentations
Le modèle de générateur est utile lorsque vous avez peu d'attributs obligatoires et de nombreux attributs facultatifs pour construire un objet. Pour créer un objet avec différents attributs obligatoires et facultatifs, vous devez fournir un constructeur complexe pour créer l'objet. Le modèle de générateur fournit un processus pas à pas simple pour construire un objet complexe.
Cas d'utilisation réel:
Différents utilisateurs de FaceBook ont des attributs différents, qui consistent en des attributs obligatoires tels que le nom d'utilisateur et des attributs facultatifs tels que UserBasicInfo et ContactInfo. Certains utilisateurs fournissent simplement des informations de base. Certains utilisateurs fournissent des informations détaillées, y compris les informations de contact. En l'absence de modèle Builder, vous devez fournir un constructeur avec tous les paramètres obligatoires et facultatifs. Mais le modèle Builder simplifie le processus de construction en fournissant un processus simple, étape par étape, pour construire l'objet complexe.
Conseils:
- Fournit une classe de générateur imbriquée statique.
- Fournit un constructeur pour les attributs obligatoires de l'objet.
- Fournit des méthodes de réglage et de lecture pour les attributs optionnels de l'objet.
- Renvoie le même objet Builder après la définition des attributs facultatifs.
- Fournit la méthode build (), qui renvoie un objet complexe
Extrait de code:
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);
}
}
sortie:
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
Explication:
FaceBookUser
est un objet complexe dont les attributs ci-dessous utilisent la composition:String userName; UserBasicInfo userInfo; ContactInfo contactInfo;
FaceBookUserBuilder
est une classe de construction statique qui contient et construitFaceBookUser
.userName
est uniquement un paramètre obligatoire pour créerFaceBookUser
FaceBookUserBuilder
construitFaceBookUser
en définissant des paramètres facultatifs:UserBasicInfo
etContactInfo
Cet exemple illustre trois FaceBookUsers différents avec des attributs différents, construits à partir de Builder.
- fbUser1 a été construit comme FaceBookUser avec l'attribut userName uniquement
- fbUser2 a été construit comme FaceBookUser avec userName et UserBasicInfo
- fbUser3 a été créé avec FaceBookUser avec userName, UserBasicInfo et ContactInfo
Dans l'exemple ci-dessus, la composition a été utilisée au lieu de dupliquer tous les attributs de FaceBookUser dans la classe Builder.
Dans les modèles de création, nous commencerons par un modèle simple, comme FactoryMethod
et FactoryMethod
vers des modèles plus flexibles et complexes, tels que AbstractFactory
et Builder
.
Java / Lombok
import lombok.Builder;
@Builder
public class Email {
private String to;
private String from;
private String subject;
private String body;
}
Exemple d'utilisation:
Email.builder().to("[email protected]")
.from("[email protected]")
.subject("Email subject")
.body("Email content")
.build();
Modèle de générateur avancé avec une expression Java 8 Lambda
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;
}
}
Ancienne voie
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);
}
Manière avancée:
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);
}
}
Usage:
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();