Condivisione dello stato con dipendenze - Progettazione orientata agli oggetti

5

Supponiamo di definire due interfacce di seguito:

public interface IReader
{
    void Read(string bookName);
}

public interface IWriter
{
    void Write(string bookName);
}

Ora voglio implementare l'interfaccia IReader in questo modo:

 public class Reader : IReader
{
    private IEnumerable<string> _books;

    public Reader(IEnumerable<string> books)
    {
        _books = books; // List of books is given through constructor
    }

    public void Read(string bookName)
    {
        if (_books.Contains(bookName))
        {
            // Reading here
        }
        else
        {
            throw new InvalidOperationException("Given book name was not found in the library.");
        }
    }
}

E ora voglio definire una classe di livello superiore che implementa entrambe le due interfacce:

public class Person : IReader, IWriter
{
    // This is the data I want to share with IReader argument of constructor
    private IList<string> _books = new List<string>();
    private IReader _reader;

    public Person(IReader reader)
    {
        _reader = reader; // How do I share books with this object?
    }

    public void Read(string bookName)
    {
        _reader.Read(bookName);
    }

    public void Write(string bookName)
    {
        _books.Add(bookName);
    }
}

Come hai notato, ho usato la composizione per implementare l'interfaccia IReader. Devo inserire un'istanza di Reader nella classe Person ma devo anche condividere i dati dei libri della mia persona con l'istanza Reader. Questo è il problema che voglio risolvere.

Finora non abbiamo fornito un modo per condividere l'elenco di libri con l'interfaccia IReader. Mi vengono in mente alcune opzioni:

Prima opzione: crea un'interfaccia IReaderFactory e la sua implementazione che crea un'istanza come questa:

public interface IReaderFactory
{
    IReader Create(IEnumerable<string> books);
}

public class ReaderFactory : IReaderFactory
{
    public IReader Create(IEnumerable<string> books)
    {
        return new Reader(books);
    }
}

Questo è tutto ok, ora posso iniettare IReaderFactory nel mio costruttore Person anziché in IReader. Il rovescio della medaglia è che richiede 2 definizioni aggiuntive IReaderFactory e ReaderFactory.

Seconda opzione: aggiungi un altro metodo all'interfaccia IReader in questo modo:

void Initialize(IEnumreable<string> books);

Anche questo funziona, nel costruttore di Person posso chiamare questo metodo e passare i miei libri ad esso. Ma non mi sembra elegante, perché ora devo ricordare chiamare questo metodo e questo metodo può essere chiamato più volte , che è qualcosa che non desiderare.

Non voglio usare un contenitore DI e risolvere un'istanza di IReader all'interno del costruttore di Person perché nasconde le dipendenze della classe Person.

Ora, qual è il modo migliore per andare in questo tipo di situazione senza violare Principio di inversione delle dipendenze ?

    
posta Mert Akcakaya 16.03.2015 - 10:15
fonte

2 risposte

3

DIP afferma che il modulo di livello superiore dovrebbe dipendere dal modulo di livello inferiore rispetto all'astrazione e tutte le implementazioni di variabili richiedono il metodo di fabbrica. Rif: DIP

Quindi, creare una Factory Class è sicuramente una buona opzione per risolvere il tuo problema.

Inoltre, è possibile iniettare IReader e Iwriter nella classe Person.

public class Person : IReader, IWriter
{
    private IReader _reader;
    private IWriter _writer;

    public Person(IReader reader, IWriter writer)
    {
       _reader = reader;
       _writer = writer;
    }

    public void Read(string bookName)
    {
       _reader.Read(bookName);
    }

    public void Write(string bookName)
    {
       _writer.Write(bookName);
    }
}

Per creare un oggetto Person puoi usare il modello Factory.

public interface IPersonFactory
{
  Person Create(IEnumerable<string> books);
}

public class PersonFactory : IPersonFactory
{
  public Person Create(IEnumerable<string> books)
  {
    IWriter = new Writer(books); // if needed use factory class here
    IReader = new Reader(books); // if needed use factory class here
    return new Person(IReader, IWriter);
  }
}
    
risposta data 17.03.2015 - 03:57
fonte
1

Una terza opzione potrebbe comportare la creazione di una classe per gestire lo stato dei tuoi libri, quindi condividere un'istanza della classe con le implementazioni Person e IReader . Questo è concettualmente simile ad avere un repository di libri o cache. L'opzione 1 o il mio suggerimento sono probabilmente le soluzioni più pulite.

Puoi fornire maggiori informazioni sul problema generale che stai cercando di modellare? Ho la sensazione che possa essere modellato in modo leggermente diverso e il tuo problema andrà via.

    
risposta data 16.03.2015 - 22:30
fonte