Abbinando oggetti di diverso tipo senza violare SOLID / minimizzare le dipendenze

2

Ho due gerarchie di ereditarietà separate che rappresentano oggetti che possono essere "abbinati" l'un l'altro per costituire un FooBarMatch (che contiene riferimenti ai partner FooBase e Bar abbinati):

                          _____________
                         | FooBarMatch |
                         |-------------|
                    ---<>|FooBase      |<>---
                   |     |Bar          |     |
                   |     |_____________|     |
                   |                         |
                   |                         |
             ______|_______          ________|_____              
            | <<abstract>> |        |      Bar     |
            |    FooBase   |        |______________|
            |______________|
                   ^
                   |
         --------------------
 _______|______       _______|______
|     FooA     |     |      FooB    |
|______________|     |______________|

La logica effettiva per determinare se una FooBase è una corrispondenza per una Bar dipende da quale sottotipo FooBase finisce per essere (se FooBase è una FooA dobbiamo eseguire una logica diversa da quella che sarebbe se fosse a FooB ). Ma tutti gli oggetti FooBase possono essere confrontati con un Bar per vedere se sono una corrispondenza.

Attualmente sto gestendo questo come segue: creando un'interfaccia IBarMatchable con un metodo IsMatch(Bar) : bool , che è implementato da un metodo astratto in FooBase . FooA e FooB quindi contengono diverse implementazioni per IsMatch(Bar) . Assomiglia a questo:

                          _____________
                         | FooBarMatch |
                         |-------------|
 _______________    ---<>|FooBase      |<>---
| IBarMatchable |  |     |Bar          |     |
|---------------|  |     |_____________|     |
| IsMatch(Bar)  |  |                         |
|_______________|  |                         |
        ^    ______|_______          ________|_____              
        |   | <<abstract>> |        |      Bar     |
         ---|    FooBase   |        |______________|
            |--------------|
            |*IsMatch(Bar)*|
            |______________|
                   ^
                   |
         --------------------
 _______|______       _______|______
|     FooA     |     |      FooB    |
|--------------|     |--------------|
|IsMatch(Bar)  |     |IsMatch(Bar)  |
|______________|     |______________|

Ora per determinare le partite possiamo riguardare solo noi stessi con IBarMatchable . Questo sembra portare a termine quello che voglio, tuttavia sono curioso di sapere se questo è "buon design" o meno-- Sono molto preoccupato che ora sembra

  1. Introduce una dipendenza da Bar a FooBase per supportare funzionalità che alla fine non rientrano in FooBase ( FooBase non si preoccupa affatto della corrispondenza). FooBase altrimenti non ha nulla a che fare con Bar .

  2. Introduce un secondo "motivo per cambiare" (ovvero il modo in cui definiamo una corrispondenza cambia) in FooBase - quindi potenzialmente una violazione SRP.

Questo viola SOLID? C'è un modo migliore per progettare ciò che non richiede FooBase per dipendere da Bar ?

    
posta Andrew 06.06.2016 - 19:45
fonte

2 risposte

1

Ci sono vari modi per farlo:

  • Come menzionato nei commenti: un metodo di estensione potrebbe realizzare la stessa cosa
  • Se vuoi continuare con l'approccio dell'interfaccia ma sei preoccupato per FooBase che ha una dipendenza su Bar , potresti implementare l'interfaccia in FooA e FooB in modo che solo loro abbiano una dipendenza su Bar (che è una dipendenza reale). Quindi lavorerai sull'interfaccia invece che sulla classe base.

In ogni caso, molto dipende dal tuo modello attuale. In un caso come questo, è meglio menzionare il modello attuale piuttosto che usare foo e bar

    
risposta data 06.06.2016 - 20:58
fonte
1

Metti la dipendenza in FooBarMatch

Molto simile a IEnumerable.GetEnumerator , implementa un IMatcher in Foo e Bar che restituisce un matcher oggetto - con un metodo IMatchable.GetMatcher (e altri se necessario).

IMatcher.MatchMeUP prenderà un oggetto controparte. Un oggetto IMatcher dovrà necessariamente conoscere i dettagli intimi per creare corrispondenze. L'oggetto FooBarMatch deve sapere che cosa, quando, come chiamare IMatcher API per creare corrispondenze e fare qualcosa con i risultati. Foo e Bar non hanno nemmeno bisogno di essere a conoscenza dell'esistenza di altre classi.

Tuttavia il diavolo è nei dettagli e ci saranno decisioni di progettazione su come Foo & Bar API pubblica "nativa" e la loro% public_de% API pubblica viene manipolata in IMatcher per rendere possibile la corrispondenza.

    
risposta data 06.08.2016 - 00:38
fonte

Leggi altre domande sui tag