存储库模式熟悉超棒的存储库模式

2025-06-07

存储库模式熟悉超棒的存储库模式

存储库模式是另一种抽象,就像计算机科学中的大多数概念一样。它适用于多种不同的语言。事实上,很多开发人员都在使用存储库模式,只是没有意识到而已。

在这篇文章中,我将改造一段代码。首先,我们先来看一下这段代码,它从数据库加载一条记录。获取到记录后,它会返回给调用者。我们来看一些代码。

需要改进

我们从数据库中加载的记录是PersonModel

public class PersonModel
{
    public string Name { get; set; }
    public int Age { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

从数据库加载人员的服务是ICompanyLogic。它由以下方法定义组成。

public interface ICompanyLogic
{
    PersonModel GetPersonByName(string name);
}
Enter fullscreen mode Exit fullscreen mode

的实施ICompanyLogic由 负责CompanyLogic

public class CompanyLogic: ICompanyLogic
{
    private IPersonDataContext _personDataContext;
    public PersonService(IPersonDataContext personDataContext)
    {
        _personDataContext= personDataContext;
    }

    public PersonModel GetPersonByName(string name)
    {
        using(var ctx = _personDataContext.NewContext())
        {
            var person = ctx.People.First(p => p.Name.Equals(name));
            return person;
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

到目前为止,情况还不算太糟。我们有一个业务服务CompanyLogic,可以从数据库中检索单个人员。

但是我们又有一个新的需求,需要一种从其他数据库加载公司信息的方法。所以我们需要添加一个新方法并进行扩展CompanyLogic

CompanyModel表示存储在公司数据库中的模型。

public class CompanyModel
{
    public string Name { get; set; }
    public int Size { get; set; }
    public bool Public { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

我们扩展了CompanyLogic一种按名称返回公司的方法。

public class CompanyLogic: ICompanyLogic
{
    private IPersonDataContext _personDataContext;
    private ICompanyDataContext _companyDataContext;
    public PersonService(IPersonDataContext personDataContext, 
                         ICompanyDataContext companyDataContext)
    {
        _personDataContext= personDataContext;
        _companyDataContext = companyDataContext;
    }

    public PersonModel GetPersonByName(string name)
    {
        using(var ctx = _personDataContext.NewContext())
        {
            var person = ctx.People.First(p => p.Name.Equals(name));
            return person;
        }
    }

    public CompanyModel GetCompanyByName(string companyName)
    {
        using(var ctx = _companyDataContext.NewContext())
        {
            var person = ctx.Company.First(c => c.Name.Equals(companyName));
            return person;
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

现在我们开始看到这个初始解决方案存在的问题了。以下是一些不太理想的地方。

  • CompanyLogic,知道如何访问两个不同的数据库。
  • 我们的using语句中存在重复的代码。
  • 我们的逻辑知道人员和公司是如何存储的。
  • GetPersonByName并且GetCompanyByName如果不引入全部,就无法重复使用CompanyLogic

除了所有这些之外,我们该如何CompanyLogic在当前状态下进行测试?我们必须模拟个人和公司的数据上下文,才能拥有真实的数据库记录。这是可以做到的。但我们的精力应该放在测试逻辑上,而不是模拟数据库对象。

实现存储库模式

存储库模式在数据访问之上添加了一个抽象层。
一点点抽象就能带来很大的帮助。使用存储库模式,我们可以添加一层薄薄的抽象来访问人员和公司数据库。然后CompanyLogic,任何其他逻辑都可以利用这些抽象。

让我们首先创建我们的IPersonRepository界面及其附带的实现。

public interface IPersonRepository
{
    PersonModel GetPersonByName(string name);
}

public class PersonRepository: IPersonRepository
{
    private IPersonDataContext _personDataContext;
    public PersonRepository(IPersonDataContext personDataContext)
    {
        _personDataContext= personDataContext;
    }

    public PersonModel GetPersonByName(string name)
    {
        using(var ctx = _personDataContext.NewContext())
        {
            return ctx.People.First(p => p.Name.Equals(name));
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

然后我们可以为公司做一些非常类似的事情。我们可以创建ICompanyRepository界面及其实现。

public interface ICompanyRepository
{
    PersonModel GetCompanyByName(string name);
}

public class CompanyRepository: ICompanyRepository
{
    private ICompanyDataContext _companyDataContext;
    public CompanyRepository(ICompanyDataContextcompanyDataContext)
    {
        _companyDataContext= personDataContext;
    }

    public CompanyModel GetCompanyByName(string name)
    {
        using(var ctx = _companyDataContext.NewContext())
        {
            return ctx.Company.First(p => p.Name.Equals(name));
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

我们现在有了两个独立的存储库。PersonRepository知道如何从人员数据库中按姓名加载指定的人员。CompanyRepository可以从公司数据库中按名称加载公司。现在让我们重构一下CompanyLogic,利用这些存储库来代替数据上下文。

public class CompanyLogic: ICompanyLogic
{
    private IPersonRepository _personRepo;
    private ICompanyRepository _companyRepo;
    public PersonService(IPersonRepository personRepo, 
                         ICompanyRepository companyRepo)
    {
        _personRepo= personRepo;
        _companyRepo= companyRepo;
    }

    public PersonModel GetPersonByName(string name)
    {
        return _personRepo.GetPersonByName(name);
    }

    public CompanyModel GetCompanyByName(string companyName)
    {
        return _companyRepo.GetCompanyByName(companyName);
    }
}
Enter fullscreen mode Exit fullscreen mode

瞧,我们的逻辑层不再了解任何数据库知识。我们已经抽象出了如何加载个人和公司数据。那么,我们获得了什么好处呢?

  • 存储库接口是可重用的。它们可以在其他逻辑层中使用,而无需进行任何更改。
  • 测试变得简单多了。我们模拟了接口响应,这样就可以专注于测试逻辑了。
  • 个人和公司的数据库访问代码集中在一个地方进行管理。
  • 可以在存储库级别进行优化。接口已定义并达成一致。之后,负责存储库的开发人员可以按照自己认为合适的方式存储数据。

存储库模式为我们提供了良好的数据抽象。它适用于多种语言。其核心在于,数据访问应该是一个单一职责接口。该接口可以注入到业务层,以添加任何额外的逻辑。

渴望了解亚马逊网络服务吗?

许多人渴望学习 Amazon Web Services。受此启发,我创建了一门课程,专注于学习如何使用 Amazon Web Services。课程重点关注静态网站的托管、安全和交付问题。您可以通过构建解决方案来学习 S3、API 网关、CloudFront、Lambda 和 WAF 等服务。

关于 AWS 的信息浩如烟海,很容易迷失方向,学习进度停滞不前。解决这个问题,我们可以梳理信息,加快学习速度。我写这本书和视频课程的目的是与大家分享我学到的知识。

听起来很有趣?点击这里,查看登陆页面了解更多信息,并选择适合您的套餐

文章来源:https://dev.to/kylegalbraith/getting-familiar-with-the-awesome-repository-pattern--1ao3
PREV
如何通过多年的职业生涯积累财富
NEXT
DevOps 是一种不断发展的文化,而不是一个团队