Compartilhando estado com dependências - Design Orientado a Objetos

5

Suponha que eu defino duas interfaces abaixo:

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

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

Agora quero implementar a interface do IReader assim:

 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 agora eu quero definir uma classe de nível mais alto que implemente as duas interfaces:

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);
    }
}

Como você percebeu, usei a composição para implementar a interface do IReader. Eu preciso injetar uma instância do Reader na classe Person, mas também preciso compartilhar os dados dos livros da minha pessoa com a instância do Reader. Este é o problema que quero resolver.

Até agora, não fornecemos uma maneira de compartilhar a lista de livros com a interface do IReader. Algumas opções vêm à minha mente:

Primeira opção: Crie uma interface IReaderFactory e sua implementação, que cria uma instância como esta:

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

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

Tudo isso é bom, agora posso injetar o IReaderFactory no meu construtor Person em vez de no IReader. A desvantagem é que requer 2 definições adicionais IReaderFactory e ReaderFactory.

Segunda opção: Adicione outro método à interface do IReader assim:

void Initialize(IEnumreable<string> books);

Isso também funciona, no construtor da pessoa eu posso chamar esse método e passar meus livros para ele. Mas não parece elegante para mim, porque agora eu tenho que lembrar de chamar esse método, e esse método pode ser chamado muitas vezes , o que é algo que não fazemos quer.

Eu não quero usar um contêiner DI e resolver uma instância do IReader dentro do construtor do Person, porque ele oculta as dependências da classe Person.

Agora, qual é a melhor maneira de entrar nesse tipo de situação sem violar o Princípio de Inversão de Dependência ?

    
por Mert Akcakaya 16.03.2015 / 10:15
fonte

2 respostas

3

O DIP declara que o módulo de nível superior deve depender do módulo de nível inferior sobre a abstração e todas as implementações variáveis requerem o método de fábrica. Ref: DIP

Então, criar uma classe de fábrica definitivamente é uma boa opção para resolver seu problema.

Além disso, você pode injetar IReader e Iwriter em sua 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);
    }
}

Para criar um objeto Person, você pode usar o padrão 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);
  }
}
    
por 17.03.2015 / 03:57
fonte
1

Uma terceira opção pode envolver a criação de uma classe para gerenciar o estado dos seus livros e, em seguida, o compartilhamento de uma instância da classe com as implementações Person e IReader . Isso é conceitualmente semelhante a ter um repositório de livros ou cache. Opção 1 ou minha sugestão são provavelmente as soluções mais limpas.

Você pode fornecer mais informações sobre o problema geral que está tentando modelar? Tenho a sensação de que pode ser modelado de forma ligeiramente diferente e o seu problema desaparece.

    
por 16.03.2015 / 22:30
fonte