Schema del costruttore in più fasi

0

Mi piace usare il pattern Builder / Director per costruire oggetti complessi. Funziona molto bene. Le uniche restrizioni (forse non sono proprio delle restrizioni) vedo che tutti i parametri per la costruzione di un oggetto devono essere presenti prima di chiamare il costruttore.

Sono giunto a una situazione in cui ho bisogno di costruire un oggetto complesso, ma una parte alla volta. Oltre a questo, ho bisogno di supportare entrambi gli scenari.

Esempio del primo scenario ( dove ho tutti i parametri necessari per costruire un oggetto complesso in una volta ): un utente chiama un punto finale api con una richiesta di build dto che contiene tutti i parametri di cui ho bisogno. Passo richiesta dto a director e costruisco l'oggetto.

Esempio del secondo scenario ( dove la costruzione di un oggetto è suddivisa in più fasi ): un utente chiama un punto finale api e passa in alcuni dto contiene solo i parametri per costruire la prima parte dell'intero oggetto. Dopo un po 'di tempo, l'utente chiama un punto finale api e passa un altro dto che contiene solo i parametri per costruire la seconda parte, e così via.

Qual è il modo migliore per gestirlo? Creo più director che creano solo quelle parti specifiche?

    
posta ColdAir 31.07.2018 - 16:50
fonte

1 risposta

0

Ci sono alcune opzioni per come la vedo io:

Opzione 1: passa il Builder Around

Non c'è alcun vantaggio nel costruire e restituire effettivamente un oggetto che dovrà essere cambiato. Basta passare l'oggetto Builder dove mai deve andare e fornire l'accesso ai suoi campi in modo che tutto ciò che deve accadere tra ogni fase di costruzione possa conoscere lo stato corrente del builder. Gli svantaggi di questo sono che non puoi "bloccare" una parte dello stato Builders se è qualcosa che devi fare. Può essere fatto tecnicamente con una funzione lockInStage1() o qualcosa che cambia un flag che impedisce l'utilizzo di alcuni setter, ma è un po 'disordinato.

Opzione 2: fornire un'implementazione ReadOnly

Questo è fondamentalmente la stessa cosa dell'opzione 1, ma senza l'oggetto Builder . Basta avere una versione mutabile dell'oggetto e quindi consentire all'utente di creare una versione immutabile da esso.

Ad esempio:

public class ReadOnlyMyObject {
    private int field1;
    private int field2;

    public ReadOnlyMyObject(MyObject obj) {
        field1 = obj.field1;
        field2 = obj.field2;
    }

    public int getField1() {
        return field1;
    }
}

public class MyObject {
    public int field1;
    public int field2;
    //fields can either be public or accessed through getters and setters

    public ReadOnlyMyObject asReadOnly() {
        return new ReadOnlyMyObject(this);
    }    
}

Personalmente, preferisco questo sul modello del builder in quanto ti lascia aperto ad avere un oggetto mutabile se è mai necessario, e perché avere una classe Builder se l'oggetto non viene costruito come un pezzo unico. Tuttavia ha lo stesso svantaggio dell'opzione 1. Non puoi realmente bloccare lo stato di ogni fase.

Opzione 3: Builder per ogni stage

Invece di un singolo oggetto e Builder controparte, devi semplicemente creare un oggetto per ogni fase e costruirlo individualmente. Il Builder per ogni fase assumerebbe quindi come parametro la fase precedente.

public class Stage1 {
    //stage 1 fields

    public class Builder {
        //Builder fields

        public Builder() { }

        //stage 1 builder functions

        public Stage1 build() {
            //build stage 1
        }
    }    
}

public class Stage2 {
    private Stage1 stage1
    //stage 2 fields

    public class Builder {
        private Stage1 stage1;
        //Builder fields

        public Builder(Stage1 stage1) {
            this.stage1 = stage1;
        }

        //stage 2 builder functions

        public Stage1 build() {
            Stage2 stage2 = new Stage2(this.stage1);
            //build stage 2
        }
    }    
}    


public class FinalObject {
    private Stage2 stage2
    //fields

    public class Builder {
        private Stage2 stage2;
        //Builder fields

        public Builder(Stage2 stage2) {
            this.stage2 = stage2;
        }

        //builder functions

        public FinalObject build() {
            FinalObject obj = new FinalObject(this.stage2);
            //build final object
        }
    }    
}

Non amo questo, perché è potenzialmente necessario creare molte classi. Tuttavia ci sono alcuni reali vantaggi per questo metodo.

  1. Ogni fase è bloccata. Una volta creata, non può essere modificata.

  2. Se è necessario aggiungere fasi tra 2 stadi esistenti è abbastanza semplice (un po 'come l'aggiunta di un oggetto a LinkedList ha un overhead molto piccolo. Per questo motivo gli oggetti stage non dovrebbero essere chiamati Stage , Stage2 o qualsiasi valore ordinale in quanto ti costringerebbe a rinominarli tutti.

Sommario

In generale, direi che se le fasi devono essere bloccate, vai con i Multiple Builder se non hai bisogno di modificare i dati in una fase precedente una volta creata. Può essere fatto, ma combatte il modello.

Se i dati di ogni fase possono essere potenzialmente modificati da ciò che accade nelle fasi successive, passa con il passaggio di Builder o fornisci una versione dell'oggetto ReadOnly.

    
risposta data 31.07.2018 - 18:14
fonte

Leggi altre domande sui tag