DI, Predefinito locale e argomento di costruzione null predefinito anziché Iniezione di proprietà: c'è un problema?

1

Ho letto il libro di Mark Seemann su DI e ho una domanda specifica riguardo all'implementazione di un Default locale.

Il libro sostiene l'iniezione di proprietà in questo caso, ma volevo chiederti se la seguente è un'alternativa più semplice e versatile: assegnare un argomento predefinito nullo nel parametro costruttore e cambiare la clausola di guardia di quella classe per assegnare il Default locale.

Ad esempio,

class B {

    var a:IA;

    public function new(a:IA = null){
        if(a == null){
            a = new DefaultA();
        }
        this.a = a;
    }
}

In questo modo, lasciamo la classe aperta all'istanza con una IA diversa

var b:B = new B(new ConcreteA());

Oltre a consentire l'istanziazione della classe senza gli argomenti del costruttore per brevità.

var b:B = new B(); // Uses DefaultA

Non dobbiamo mai preoccuparci della nullità di una proprietà, né della creazione di metodi di iniezione di proprietà con clausole di protezione, poiché il nostro costruttore garantisce che non sarà nullo.

Inoltre, per gli utenti che creano una nuova istanza di B , = null indica sia che è facoltativo E che è possibile passare una dipendenza diversa; in tutti gli altri casi con DI non avremmo mai uno scenario parameter = null predefinito perché i nostri argomenti del costruttore sarebbero delle dipendenze non opzionali.

Come vantaggio, possiamo combinare il costruttore per consentire sia le implementazioni predefinite che quelle che richiedono una classe concreta passata.

class B {

    var a:IA;
    var c:IC;

    public function new(a:IA, c:IC = null){
        if(a == null){
            throw NullException;
        }
        this.a = a;

        if(c == null){
            c = new DefaultC();
        }
        this.c = c;
    }
}

Così come fare cose come

if(c == null){
    c = new DefaultC(a); // If our DefaultC depends on an IA
}
this.c = c;

Quali sono gli aspetti negativi di questo metodo? Mi rendo conto che ora abbiamo inserito un po 'di logica nel costruttore, ma in realtà funziona come una clausola di protezione predefinita in un modo simile che chiameremmo un setter con un parametro Local Default nel costruttore se si utilizza l'iniezione di proprietà.

Questo metodo sembra troppo ovvio per non essere stato raccomandato, quindi c'è qualcosa che mi manca per il motivo per cui ciò non va bene per l'accoppiamento / l'estendibilità / l'ingannevole / etc?

    
posta Danny Yaroslavski 08.05.2017 - 13:36
fonte

1 risposta

0

La tua idea funziona bene se esiste una sola dipendenza opzionale, ma inizia a scomparire quando ci sono più dipendenze opzionali.

class B {

    var a:IA;
    var c:IC;

    public function new(a:IA = null, c:IC = null){
        if(a == null){
            a = new DefaultA();
        }
        this.a = a;

        if(c == null){
            c = new DefaultC();
        }
        this.c = c;
    }
}

Con questa classe, diventa già ingombrante usare una A predefinita e una C. personalizzata. Non puoi semplicemente usare

var b:B = new B(new ConcreteC());

perché ciò crea un'istanza del B con un A personalizzato (che è un'istanza ConcreteC e molto probabilmente non è conforme all'interfaccia IA ) e un C predefinito. Per utilizzare un C personalizzato, devi effettivamente utilizzare

var b:B = new B(null, new ConcreteC());

quindi devi dichiarare esplicitamente che A è un puntatore nullo. E se devi specificare comunque il tuo argomento a , allora potresti facilmente lasciare il supporto per i valori predefiniti e richiedere all'utente di usare

var b:B = new B(new DefaultA(), new ConcreteC());
    
risposta data 08.05.2017 - 15:27
fonte

Leggi altre domande sui tag