参考:http://designpattern.ninja/news/2017/01/13/why-repositories-should-be-domain.html
Let’s discuss why repositories are a domain concern.
Nowadays domain-driven design (from now, just DDD) is one of top trending programming paradigms since some years when any organizations think about implementing well tailored enterprise-grade solutions.
And then many of us ask ourselves a lot of questions because we’re worried about architecting our solutions in the right way. Probably you already know that implementing a DDD-style architecture turns into deciding what’s domain, infrastructure, application… Whenever you’re going to design an interface or an implementation, you end up asking yourself: where I put it? (actually experience is a good friend to go forward because finally you build a skillset and know-how meaning that you’re not always asking yourself the same question all over again…).
Inside DDD-ish solutions you need to implement repositories, because you want to keep your domain absolutely agnostic to how your domain objects are being persisted and also how they’re retrieved from the underlying storage engine. Also, you don’t want to repeat yourself, therefore centralizing querying and write operations in a single place (i.e. the repository) will enforce code reusability since many domain services will call repository’s operations and they will focus their responsibility on implementing higher-level domain operations like calculations, decision making…
But… are repositories domain?
Why repositories aren’t an infrastructure concern
There’s a certain tendency on pointing out that repositories are an infrastructure concern. I could summarize the reasons I’ve found around the net about that statement:
Repositories are coupled with data mapping layer, or directly with a NoSQL, relational or file API, which all of them are infrastructure concerns.
Repository contracts (i.e. interfaces in most OOP languages) are infrastructure concerns.
Actually, both statements are right. Both #1 and #2 are founded in the fact that usually all repositories share some fundamental operations like add, update, remove, get by id and list. For example, in C# you would design an interface like this:
// T is a generic type parameter which will be a concrete domain object
// type once we implement this interface into some class.
public interface IRepository<T>
{
void Add(T domainObject);
void Update(T domainObject);
void Remove(T domainObject)
T GetById(T domainObject);
IList<T> List(int skip = 0, int take = 0);
}
And, probably, if you want to share some basic behaviors across your entire project, you would implement an abstract class which would be derived by any concrete repository:
public abstract class Repository<T> : IRepository<T>
{
public virtual void Add(T domainObject)
{
if(domainObject == null)
throw new ArgumentNullException("domainObject");
// Anything that should be done before actually adding
// the domain object to the underlying store should be done here.
// Once whatever stuff has been already done, we call DoAdd(...)
// to let a concrete repository implementation persist given
// domain object.
DoAdd(domainObject),
}
protected abstract void DoAdd(T domainObject);
// Rest of IRepository<T> method implementations either implemented
// as abstract members or like Add(...), we could provide some basic
// argument validation or a lot of other stuff. But we want to keep
// this sample code as simple as possible.
}
Hence, because both contract and abstract implementation aren’t specific to a domain, we would conclude that they should be an infrastructure concern (and so they’re!).
My other conclusion is that above described approach is an implementation detail, and it’s not necessarily the repository pattern per se even when I would really advocate to always define a repository pattern interface and a basic abstract class to avoid repeating yourself across your project when you need to implement things that should affect it entirely.
Let’s move on to the next and definitive argument
When architecting a DDD solution, there’s a simple rule that says define a repository to each aggregate root, right? For example, if we’ve an invoicing domain, usually you define domain objects like these:
Invoice
InvoiceLine
…probably others.
Our aggregate root is Invoice, because an invoice can live alone while an invoice line lives inside an invoice. I shouldn’t be mistaken on this.
So we define a repository interface to handle invoices:
// We also implement IRepository<T> to don't repeat ourselves... We really
// want to avoid defining GetById, Add, Remove... all over again...! Thus,
// we focus on providing domain-specific repository operations.
public interface IInvoiceRepository : IRepository<Invoice>
{
// Retrieves all invoice lines from a given invoice by its identifier.
IList<InvoiceLine> GetInvoiceLines(Guid invoiceId);
}
Stop here. Note how IInvoiceRepository is heavily tied to two specific domain inhabitants: Invoice and InvoiceLine.
Are Invoice and InvoiceLine domain? Absolutely, yes they’re domain objects of Invoicing domain. And what’s handling the whole repository? It mediates between the domain and data mapping layer so holds dependencies to both layers… No! This couldn’t be true.
Modern software development has a heavily foundation on another paradigm/design pattern which you should already know: dependency injection and inversion of control. And also follow up SOLID principles (not every principle, but at least we should get inspired by them). So, aren’t you coupling your code against interfaces instead of classes? If the answer is yes, I would ask myself: does IInvoiceRepository has any dependency with the data mapping layer? No. But it’s absolutely tied to the domain layer, because it handles specific domain objects!
Conclusion: repository is domain per se. And it’s tightly coupled both to other domain concerns as long with the data mapping layer.
相关推荐
Since Maven 3.8.1 http repositories are blocked. Possible solutions: - Check that Maven settings.xml does not contain http repositories - Check that Maven pom files do not contain ...
清楚_remote.repositories脚本文件
repositories for sbt
快速删除maven仓库repositories.bat
repositories
《repositories.xml:Maven仓库配置解析》 在Java开发领域,Maven作为一款强大的项目管理和构建工具,其核心配置文件之一就是`repositories.xml`。这个文件在我们的案例中是以`.zip`格式压缩的,名为`repositories....
$this->app->bind('App\Repositories\UserRepository', 'App\Repositories\EloquentUserRepository'); } ``` 这样,当我们在控制器或其他服务提供者中通过依赖注入使用`UserRepository`时,Laravel会自动解析并...
namespace App\Repositories; interface UserRepositoryInterface { public function getAll(); public function find($id); public function create(array $data); public function update($id, array $data);...
Implementing Domain-Driven Design will impart a treasure trove of knowledge hard won within the DDD and enterprise application architecture communities over the last couple decades.
领域模型是业务逻辑的抽象表示,它包含了业务领域的实体(Entities)、值对象(Value Objects)、领域服务(Domain Services)和仓储(Repositories)等元素。在充血模式下,这些组件拥有丰富的业务逻辑,而不仅仅是...
jarMAVENjarMAVENjarMAVENjarMAVENjarMAVENjarMAVENjarMAVENjarMAVENjarMAVENjarMAVENjarMAVENjarMAVENjarMAVENjarMAVENjarMAVENjarMAVENjarMAVENjarMAVENjarMAVENjarMAVENjarMAVENjarMAVENjarMAVENjarMAVENjarMAVENjarMAVENjarMAVENjarMAVENjarMAVEN
`repositories` 文件在 `stable-diffusion-webui` 中扮演着核心角色,它包含了项目的源代码仓库,用于自动化安装和管理这些模型的依赖。 `CodeFormer` 可能是一个代码生成模型,它能够根据用户的指令或者已有代码...
SSM
在Laravel框架中,"core-domain"通常指的是应用的核心领域逻辑,它包含了业务规则、实体、服务、领域事件等关键组件。在这个项目中,“多明尼奥-内戈西奥核心公园”可能是一个示例应用,用于展示如何在Laravel中组织...
There are a few valid reasons why corporates want to have their own repositories to host some crucial Docker images. This means that publicly available repositories are found unsuitable for storing ...