È sbagliato creare classi il cui unico scopo è di essere convertito implicitamente in un'altra classe?

10

Immagina una situazione in cui utilizziamo una libreria che ti consente di creare oggetti Circle , in cui puoi specificare il raggio e il centro del cerchio per definirlo. Tuttavia, per qualche motivo, richiede anche un parametro flavour richiesto. Ora diciamo che ho davvero bisogno di usare Circle nella mia app, ma per gli scopi della mia app posso impostare il sapore in Flavours.Cardboard ogni volta.

Per "risolvere" questo, creo la mia classe Circle in uno spazio dei nomi diverso, che accetta solo radius e center come parametri, ma ha un convertitore implicito per la classe Circle della libreria esterna che solo crea un oggetto Circle(this.radius, this.center, Flavours.Cardboard) . Quindi ovunque ho bisogno dell'altro tipo di Circle , lascio che la conversione automatica abbia luogo.

Quali sono le conseguenze della creazione di una tale classe? Ci sono soluzioni migliori? Farebbe qualche differenza se la mia applicazione fosse un'API costruita su questa libreria esterna, destinata all'uso da parte di altri programmatori?

    
posta user3002473 28.05.2016 - 03:50
fonte

2 risposte

13

Sebbene non sia sempre non valido, è piuttosto raro che le conversioni implicite siano la soluzione migliore.

Ci sono problemi.

  1. Le conversioni implicite non sono molto leggibili.
  2. Dato che stai creando un nuovo oggetto, le modifiche all'oggetto originale non verranno viste da chi stai convertendo, causando bug.
  3. Se stai buttando via l'oggetto, questo è un extra di spazzatura da pulire.
  4. Se c'è un problema, accadrà quando si verifica la conversione, non quando la cosa viene creata, creando bug più difficili da rintracciare.

In generale, ci sono soluzioni migliori.

  1. Crea il tuo involucro sottile che utilizza internamente l'altra classe / framework.
  2. Crea un metodo di supporto che tenga gli argomenti del constuctor che desideri e fornisca quello corretto, restituendo l'oggetto reale senza dover specificare l'argomento di cui non ti interessa.
  3. Eredita dalla classe del problema e fornisci il tuo costruttore più bello.
  4. Rendi conto che passare l'argomento extra non è davvero un grosso problema.

Personalmente, trovo che il n. 2 sia il più semplice da implementare e il meno oneroso sul design. Gli altri possono andare bene, data la situazione e che altro stai cercando di fare con queste lezioni.

La conversione implicita è l'ultima risorsa, e mi sembra davvero valsa la pena quando ho i funtori in stile C ++ che sto cercando di fare - gli oggetti di strategia vengono convertiti implicitamente in tipi di delegati.

    
risposta data 28.05.2016 - 06:39
fonte
1

Dato lo scenario che stai descrivendo, puoi pensare a questo in termini di applicazione di funzioni parziali.

Un costruttore è una funzione (almeno in teoria, in C #, puoi creare una "funzione fabbrica" che chiama il costruttore):

Func<double, Point, Flavour, Circle> MakeCircle = (r, p, f) => new Circle(r, p, f);

per l'applicazione parziale, il seguente sarà sufficiente:

public static Func<T1, T2, R> Partial<T1, T2, T3, R>(this Func<T1, T2, T3, R> func, T3 t3)
   => (t1, t2) => func(t1, t2, t3);

Ora puoi ottenere il tuo costruttore che richiede solo 2 parametri:

Func<double, Point, Circle> MakeCardboardCircle = Circle.Partial(Flavours.Cardboard)

Quindi ora hai una funzione di fabbrica con i tuoi parametri desiderati

Circle c = MakeCardboardCircle(1.0, new Point(0, 0)))

A proposito, questo è chiaramente equivalente all'opzione 2 sopra, solo da una prospettiva più funzionale.

    
risposta data 31.05.2016 - 00:12
fonte