Pattern creativo per creare o restituire un oggetto da altri oggetti

0

Un problema che ho riscontrato e che non ha mai avuto una buona risposta è: qual è il modello di progettazione corretto per creare o restituire un oggetto da un altro oggetto o più oggetti?

Tradizionalmente ho appena creato un Factory e ho avuto il sorgente come argomento:

#!/usr/bin/env groovy
class Foo {
    String bar
}

class FooFactory {
    Foo createFoo(Map mapWithBar) {
        Foo foo = new Foo()
        foo.bar = mapWithBar.get('bar')
        foo
    }
}

assert 'Hello, World!' == new FooFactory().createFoo(['bar': 'Hello, World!']).bar

La fabbrica è davvero il nome corretto per questo modello?

Che cosa succede quando vuoi incapsulare la logica pseudo-creazionale che ha più fonti possibili, o forse l'oggetto è già stato creato?

Ad esempio, supponi che bar sia in list of Strings (cioè cli args), imposta bar da quello, altrimenti se Foo esiste già in qualche struttura dati, usa quel foo , altrimenti crea un nuovo Foo con un bar predefinito:

#!/usr/bin/env groovy
class Foo {
    String bar
}

class FooFactory {
    Foo createFoo(List<String> args, Map mapContainingFoo, String defaultBar) {
        if (args?.size > 0) {
            def foo = new Foo();
            foo.bar = args[0];
            return foo;
        } else if (mapContainingFoo?.containsKey('foo')) {
            return mapContainingFoo.get('foo');
        } else {
            Foo foo = new Foo();
            foo.bar = defaultBar;
            return foo;
        }
    }
}

def fooFactory = new FooFactory();
assert 'args' == fooFactory.createFoo(['args'], ['foo': new Foo(bar: 'fromMap')], 'default').bar
assert 'fromMap' == fooFactory.createFoo(null, ['foo': new Foo(bar: 'fromMap')], 'default').bar
assert 'default' == fooFactory.createFoo(null, null, 'default').bar

Esiste un modello di progettazione migliore per incapsulare questa logica? Factory è il termine corretto? È ancora pari a Factory poiché non sta necessariamente creando Foo ?

Nota che sto usando solo groovy per facilità di dimostrazione, sono principalmente interessato al modello di design e non a un modo idiomatico di farlo in groovy.

    
posta Nathanial 28.02.2017 - 21:35
fonte

2 risposte

1

Stai tranquillo, Factory è lo schema / termine corretto.

Uno dei tanti esempi è: il prodotto cache AppFabric ha una classe DataCacheFactory. La factory potrebbe new () su oggetti sottostanti che stabiliscono connettività al server cache; o utilizzare oggetti connessi esistenti.

    
risposta data 01.03.2017 - 18:10
fonte
0

Hai fatto bene a scegliere il modello di fabbrica e l'implementazione mi sembra soddisfacente (IMHO).

What happens when you want to encapsulate pseudo-creational logic that has multiple possible sources, or possibly the object is even already created?

Come sai, Pattern di fabbrica nasconde la logica di creazione in modo da non dover ripetere tale logica in tutto il progetto. Se la logica è troppo semplice o troppo complessa dipende dal progetto (e quest'ultimo dipende dai requisiti). In ogni caso, il fatto è di fornire la responsabilità al / i componente / i specifico / i.

Is it even still a Factory since it isn't necessarily creating Foo?

Sì, lo è. Guardalo dal punto di vista del cliente (consumatore di fabbrica). Forniresti solo gli argomenti per ottenere un nuovo Foo. Questo è tutto. Quello che sta succedendo sotto il cofano non è affar tuo.

Torna all'esempio. Ti suggerirei alcune modifiche.

class Foo {
    String bar       
}

class FooFactory {
    Foo createFoo(List<String> args, Map mapContainingFoo, String defaultBar) {
        if (mapContainingFoo?.containsKey('foo')) {
            return mapContainingFoo.get('foo').clone();
        }
        def foo =new Foo();
        foo.bar = defaultBar;

        if (args?.size > 0) { 
            foo.bar = args[0];
        } 
        return foo;
    }
}

Suppongo sia un codice di esempio, tuttavia, ho riordinato il blocco if-else. Se questo è importante.

La modifica che conta (IMO) è:

//If foo is not clonable, make a copy.
mapContainingFoo.get('foo').clone();

La ragione è semplice. Quando chiamo una fabbrica mi aspetto un nuovo oggetto di marca, slegato dai parametri di input.

    
risposta data 31.03.2017 - 23:21
fonte

Leggi altre domande sui tag