具有依赖倒置的架构(在 DI 框架之前)

architecture with Dependency Inversion (prior to a DI Framework)

我正在学习D.I。 我的架构有一些问题,也许我遗漏了一些要点。

假设我有这个非 DI 代码(我从文件中读取了 "Person" 的列表)

static void Main()
{
   PersonReaderFromFile personReader = new PersonReaderFromFile("path-to-file");
   Person p = personReader.GetNext();  //return a Person parsed from file line or NULL at EOF
}

class Person 
{
    //stuffs here
}

class PersonReaderFromFile
{
    public Person GetNext()
    {
        Person person = new Person();
        //some logic
        return person;
    }
}

首先,为了实施 D.I。模式,我需要接口,所以我做

static void Main()
{
   iPersonReader personReader = new PersonReaderFromFile("path-to-file");
   iPerson p = personReader.GetNext();
}

interface iPerson
{
}

class Person : iPerson
{
}

interface iPersonReader
{
    iPerson GetNext();
}

class PersonReaderFromFile : iPersonReader
{
    public iPerson GetNext()
    {
        Person person = new Person();
        //some logic
        return person;
    }
}

现在我的问题是:PersonReaderFromFile 取决于 Person 实现。 没关系? 或者我需要一个额外的 class,比如 PersonFactory?

static void Main()
{
    iPersonFactory factory = new PersonFactory();
    iPersonReader personReader = new PersonReaderFromFile("path-to-file", factory);
    iPerson person = personReader.GetNext();
}

interface iPerson
{
}

class Person : iPerson
{
}

interface iPersonReader
{
    iPerson GetNext();
}

class PersonReaderFromFile : iPersonReader
{
    iPersonFactory _factory;

    public PersonReaderFromFile(iPersonFactory factory)
    {
        _factory = factory;
    }

    public iPerson GetNext()
    {
        Person person = _factory.CreateNewPerson();
        //some logic
        return person;
    }
}

interface iPersonFactory 
{
    iPerson CreateNewPerson();
}

class PersonFactory : iPersonFactory
{
    iPerson CreateNewPerson()
    {
        Person person = new Person();
        return person;
    }
}

现在 PersonFactory 依赖于 Person 实现,但它应该是正确的。 有什么建议吗? Tnx to all.

编辑: 我展示了一个示例 PersonReaderFromFile 实现

class PersonReaderFromFile
{
    StreamReader _fileReader;

    public PersonReaderFromFile(string path)
    {
        _fileReader = new StreamReader(file);
    }

    public Person GetNext()
    {
        string line = _fileReader.ReadLine();
        if (line == null)
        {
                _fileReader.Close();
                return null;
        }

       string name, lastName, email;
       ParseInformationFromLine(line, out name, out lastName, out email);

       Person p = new Person { Name = name, LastName = lastName, Email = email };

       return p;
    }

   private ParseInformationFromLine(string line, out string name, out string lastName, out string email)
   {
        //I don't think that matters
   }
}

PersonReaderFromFile 不依赖于 Person。 class 似乎只是一个代表 运行 时间数据的 POCO。

PersonReaderFromFile 依赖于 StreamReader 以及 ParseInformationFromLine 函数

先抽象出那些实现细节到自己的关注点。

public interface IReadLines {
    string ReadLine();
}

public interface IParsePersonInformationFromLine {
    void ParseInformationFromLine(string line, out string name, out string lastName, out string email);
}

目标 class 将明确依赖于抽象

public class PersonReaderFromFile {
    private readonly IReadLines reader;
    private readonly IParsePersonInformationFromLine parser;

    public PersonReaderFromFile(IReadLines reader, IParsePersonInformationFromLine parser) {
        this.reader = reader;
        this.parser = parser;
    }

    public Person GetNext() {
        string line = reader.ReadLine();
        if (line == null) {
            return null;
        }

        string name, lastName, email;
        parser.ParseInformationFromLine(line, out name, out lastName, out email);

        Person p = new Person { Name = name, LastName = lastName, Email = email };

        return p;
    }
}

各个抽象将有自己的实现来满足将在 运行 时使用的所需功能。例如 reader 内部仍会使用 StreamReader 来获取行。 PersonReaderFromFile 不需要知道如何检索该行。只是它在调用时需要一条线。

Main 现在可以重构为例如使用 Pure DI

static void Main() {
    IReadLines reader = new ReadLinesImplementation("path-to-file");
    IParsePersonInformationFromLine parser = new ParsePersonInformationFromLine(); 
    PersonReaderFromFile personReader = new PersonReaderFromFile(reader, parser);
    Person p = personReader.GetNext();  //return a Person parsed from file line or NULL at EOF
}

可以应用进一步的重构,但这只是一个简化的示例,用于识别应该从与实现问题紧密耦合的代码中抽象出来的实现细节。