Modelli di progettazione del generatore: passaggio dei parametri dal client al builder

3

Il modello di progettazione del costruttore consente di passare i parametri? Se sì, qual è il modo giusto per raggiungerlo?

Panoramica

Il pattern del builder nasconde i dettagli del costrutto dell'oggetto, posiziona due livelli di astrazione tra il prodotto e il client: builder e director

  • builder è l'interfaccia per la costruzione del prodotto, l'idea è polimorfismo: gli stessi metodi sono usati per impostare diversi prodotti
  • director separa il cliente dal processo di costruzione
  • Il pattern Builder è pensato per prodotti complessi, quindi l'interfaccia del builder potrebbe essere grande: setPart1() , setPart2() , ... setPart100()
  • director ha un'interfaccia piccola e semplice: constructProduct() , getProduct()
  • lo stesso director potrebbe utilizzare diversi builder di calcestruzzo per diversi prodotti in calcestruzzo
  • ma anche la stessa interfaccia builder può essere utilizzata da diversi amministratori

Che cosa succede se alcune proprietà del prodotto non possono essere nascoste dal client.

Esempio di problema

Supponiamo di avere il prodotto complesso come il set di computer.

class ComputerSet {
private:
    string procName;
    string hddName;
    int hddCapacity;
public:
    ComputerSet(string p) : procName(p) {}
    void setHdd(string name, int capacity);
};

void ComputerSet::setHdd(string name, int capacity) {
  hddName = name;
  hddCapacity = capacity;
}

In realtà, non è così complesso. Il prodotto ha solo 3 parti da impostare: procName , hddName , hddCapacity . Il motivo è di rendere piccolo l'esempio. Diciamo che il set del computer potrebbe avere molti componenti.

Dividere la parte HDD in due parti ( nome e capacità ) è stata fatta per la semplicità dell'esempio. Hanno una natura diversa: hddName è costante costitutiva , hddCapacity è builder-variant .

Supponiamo che ci sia il prodotto concreto: set di computer con procName="Amdel" e hddName="Orange" . Questi dettagli potrebbero essere nascosti dal client. Il cliente:

  • crea l'istanza di Director
  • crea l'istanza di AmdelBuilder
  • passa AmbelBuilder al direttore
  • utilizza l'interfaccia di Director per ottenere il prodotto
  • non conosce le stringhe "Amdel" e "Orange"

Ma ci potrebbero essere molte capacità di HDD da scegliere: 250, 500, 750, 1000, 1500, 2000.

Un modo è creare il costruttore per ogni capacità: AmdelBuilder250, AmdelBuilder500, AmdelBuilder750, AmdelBuilder1000, AmdelBuilder1500, AmdelBuilder2000.

Che ne dici di progettare solo un AmbelBuilder per ogni capacità e passare il parametro hddCapacity appena prima della creazione del prodotto? Come passare il parametro:

  • contenerlo all'interno del builder come sua proprietà (membro dei dati); due tipi di impostazioni sia dal livello client

    • impostato con il costruttore (una volta per istanza)
    • impostato con il setter (impostazione di più valori per singola istanza)
  • rendi l'argomento del metodo builder , deve essere passato dal livello director

    • diventa l'argomento del metodo di costruzione del director
    • lo contengono all'interno del director come sua proprietà (membro dei dati)

Primo approccio

Il Builder memorizza hddCapacity come proprio campo dati

class Builder {
protected:
    ComputerSet *cs;
    int hddCapacity;
public:
    Builder(int capacity = 250) : hddCapacity(capacity) {  }
    virtual void createComputerSet() = 0;
    virtual void setHdd() = 0;
    ComputerSet* returnComputerSet() { return cs; }
};

Il metodo setHdd() del generatore di calcestruzzo non richiede parametri

class AmdelBuilder : public Builder {
public:
    void createComputerSet();
    void setHdd();
    AmdelBuilder(int capacity = 500) : Builder(capacity) { }
};

void AmdelBuilder::createComputerSet() {
    cs = new ComputerSet("Amdel");
}
void AmdelBuilder::setHdd() {
    cs->setHdd("Orange", hddCapacity);
}

Il regista non conosce il parametro hddCapacity

class Director {
private:
    Builder *builder;
public:
    void setBuilder(Builder *b) { builder = b; }
    void constructComputerSet();
    ComputerSet* getComputerSet() { return builder->returnComputerSet(); }
};

void Director::constructComputerSet() {
    builder->createComputerSet();
    builder->setHdd();
}

perché il client imposta AmdelBuilder.hddCapacity quando il client crea l'istanza Builder

Director* d = new Director();
Builder* ba = new AmdelBuilder(750); // Amdel + Orange HDD 750
d->setBuilder(ba);
d->constructComputerSet();
ComputerSet* csa750 = d->getComputerSet();

Altra soluzione

Il generatore non memorizza hddCapacity , ma il metodo setHdd() richiede il parametro hddCapacity .

class Builder {
protected:
    ComputerSet *cs;
public:
    Builder() {  }
    virtual void createComputerSet() = 0;
    virtual void setHdd(int hddCapacity) = 0;
    ComputerSet* returnComputerSet() { return cs; }
};

Il director è l'utente diretto dell'API del builder. Quindi il regista deve conoscere il valore hddCapacity .

Domanda

Quale dovrebbe essere la migliore pratica che non viola i principi OO e l'idea di incapsulamento del modello di builder?

    
posta user2314351 06.04.2015 - 12:26
fonte

1 risposta

1

Credo che nessuno dei tuoi approcci possa violare nulla ed entrambi possono essere usati bene.

Il passaggio dei parametri al builder può essere fatto usando i metodi del costruttore o del setter. Non vedo alcun problema con esso.

Tendo a passare i parametri tramite il costruttore se non ce ne sono così tanti. Se ho più di 3-5 parametri di configurazione, utilizzo i metodi per configurare Builder.

    
risposta data 18.04.2015 - 18:05
fonte

Leggi altre domande sui tag