Quando vale NON usare una fabbrica?

2

In questi giorni sto impiegando un TDD e mi sto davvero divertendo - tutto sembra scorrere meglio ed essere naturalmente meglio costruito e organizzato. Tuttavia, mentre scrivevo un po 'di codice IO, utilizzando System.IO.Stream s, e mi stavo chiedendo - quando mai vale la pena non usare una fabbrica? Perché in caso di Stream s, sicuramente sembra meglio non usare una fabbrica.

In generale, per i tipi più complessi che ho definito, come una classe che controlla l'autenticazione di qualcosa e le interfacce con un database, probabilmente si utilizzerà un contenitore di dipendenze per l'iniezione e si risolve in runtime senza mai aver bisogno di in realtà creane uno.

Tuttavia, in alcune circostanze, quando devi creare molte di queste istanze, devi creare una Factory per costruire quel tipo - come ad esempio:

class Foo
  Foo(Bar bar, Foobar foobar, Fuzz fuzz)
  ...
end

Qui, perché non vuoi esporre come creare direttamente questo oggetto ai client che ne hanno bisogno, esponi una Factory che le creerà e le inserirà nel client. Questo ha il vantaggio di permetterti di sostituire la fabbrica in qualsiasi momento tu voglia con qualcos'altro ed è generalmente usato per creare istanze di tipi che hanno tipi derivati.

class FooFactory
   void Create(Bar, Foobar, Fuzz)
end

Tuttavia, tornando al mio punto Stream - varrebbe la pena di creare una fabbrica per un decoratore attorno a un flusso? Ad esempio, nel mio progetto ho BinaryDataStream , che legge i miei dati da uno Streeam. BinaryData è in un formato personalizzato e accetta un argomento Stream nel suo costruttore. L'utilizzo di new sembra violare tutto ciò che so che ho imparato da quando ho iniziato a utilizzare TDD, perché sto dando il dipendente in cui ha bisogno di sapere esplicitamente come ottenerlo è un collaboratore Tuttavia una fabbrica sembra eccessivo.

Pensieri?

EDIT: Penso di aver bisogno di chiarire. Non intendo evitare sempre new (), poiché ovviamente ha il suo uso nel legare le dipendenze e cose simili. tuttavia , intendevo nella seguente situazione (copia-pasta dai commenti):

What I meant was that I have been told it is intrinsically evil to use the new() operator to a collaborator from inside the type that uses the collaborator, and that it is better to either a) pass an injected type or b) pass a factory (if you need to create an unknown number of those types). By using new() inside the collaborator you tie how to create that object and where to create it directly to the thing that requires it, and that it is better to inject a preconfigured instance into the constructor if you need one instance of it, or inject a factory into the constructor if you need to create multiple/undetermined number of instances

    
posta Dan Pantry 16.04.2014 - 19:45
fonte

2 risposte

16

Here, because you don't want to expose how to directly create this object to the clients that need it, you expose a Factory that will create them and inject that into the client instead.

  1. Se i client sanno che l'oggetto esiste, di solito è bene per loro sapere come farlo. Se hai un'interfaccia allora forse hai bisogno di qualche factory per creare l'istanza concreta, ma per TDD ti stai solo prendendo in giro comunque.
  2. La tua factory di esempio è solo un passthru. Il tuo cliente sa già tutto ciò che è necessario per costruire l'oggetto, quindi sostituire la fabbrica è tanto difficile quanto sostituire la chiamata del costruttore.

When is it worth NOT using a Factory?

Questa è la modalità di pensiero sbagliata.

È preferibile non utilizzare le fabbriche. Le fabbriche sono necessarie solo quando è necessario astrarre l'oggetto creazione . Dato che dovresti (in generale) limitare la creazione di oggetti che richiedono tale astrazione, dovresti usare le fabbriche con parsimonia. Invece, la maggior parte dei tuoi oggetti prenderà solo un'interfaccia e non gli interesserà da dove proviene.

Aggiungi la complessità solo quando è necessario.

    
risposta data 16.04.2014 - 20:10
fonte
1

Perchè qualsiasi modello di fabbrica sia utilizzabile, ha bisogno di un parametro per sapere quale istanza concreta creare. Con Factory Method e Abstract Factory questo "parametro" è di tipo è attivo il metodo di creazione, che si ottiene con il polimorfismo. Con il modello di fabbrica "semplice", l'unico modo per ottenere questo è passare il parametro nel metodo di creazione. Inoltre, questo processo di creazione dovrebbe essere complesso, non solo basato su enum, catena if-else o qualcosa del genere. Vale anche la pena quando ci sono più posti diversi in cui viene utilizzata la fabbrica.

Se hai una classe factory che non ha parametri di metodo, la logica di creazione è semplice o è usata solo in un posto solo, quindi considererei inutile ipersensibilità e astrazione inutile. Il metodo semplice sarebbe sufficiente.

Inoltre, solo perché la creazione è in una classe diversa, non significa che sia disaccoppiata. Il codice chiamante è ancora strongmente legato alla classe Factory. Dovresti usare la fabbrica astratta per avere un codice veramente disaccoppiato. Inoltre, tutta la mentalità del "nuovo è cattivo" è pericolosa, dovresti lasciar perdere. La creazione di oggetti è una parte importante del codice OOP. Cercando di incapsulare anche quello si tradurrà rapidamente in overengineering e astrazioni inutili. Si noti inoltre che i costruttori stessi sono una sorta di fabbriche. Assicurano che l'istanza sia creata in una base di stato valida e per farlo, chiedono i dati richiesti.

    
risposta data 16.04.2014 - 20:00
fonte

Leggi altre domande sui tag