我有以下伪代码
public class ClientService
{
private readonly IClientsRepository clientsRepository;
private readonly IClientsCache clientsCache;
public ClientService(IClientsRepository clientsRepository,
IClientsCache clientsCache)
{
this.clientsRepository = clientsRepository;
this.clientsCache = clientsCache;
this.clientsRepository.OnClientCreated += OnNewClient;
}
public IList<ClientDto> GetAllClients()
{
var result = clientsCache.GetClients();
if (result == null)
{
result = clientsRepository.GetClients();
for (int i = 0; i < result.Count; i++)
{
clientsCache.AddClient(result[i]);
}
}
return mapped clients...
}
public void AddClient(Clients newClient)
{
clientsRepository.Insert(newClient);
}
private void OnNewClient(Clients newClient )
{
clientsCache.AddClient(newClient);
}
}
public interface IClientsRepository
{
event ClientCreated OnClientCreated;
IList<Client> GetClients();
void Insert(ClientsCache client);
}
public class ClientsRepository : IClientsRepository
{
public event ClientCreated OnClientCreated;
public IList<Client> GetClients()
{
Get clients from database...
}
public void Insert(ClientsCache client)
{
//code to save to database...
OnClientCreated?.Invoke(client);
}
}
public interface IClientsCache
{
IList<Client> GetClients();
UpdateClients(IList<Client> clients);
AddClient(Client client);
DeleteClient(Client client)
}
public class ClientsCache : IClientsCache
{
private readonly List<Clients> clientsCache;
public ClientsCache()
{
clientsCache = new List<Clients>();
}
public IList<Client> GetClients()
{
return clientsCache;
}
public void UpdateClients(IList<Client> clients)
{
clientsCache = clients;
}
public void AddClient(Client client)
{
clients.add(client);
}
public void DeleteClient(Client client)
{
clients.remove(client);
}
}
如您所见,有一个存储库可以从数据库中获取客户端。问题是我不想每次需要所有客户端时都去数据库,所以我缓存它们。 我对此有几个问题:
- 缓存是否进入基础架构层?
- 我是否需要另一个存储库才能从缓存中获取客户端?或者最好使用从缓存中获取客户端的服务。
- 如果我创建一个新客户端,我需要将他添加到数据库中,然后将其也添加到缓存中。我是否需要其他服务来实现此目的?
1. 缓存
通常它应该保留在基础结构层中。在这里,您可以"调整"您的阅读量,并根据 UI 需求使其更快。因此,您可以在不弄乱域的情况下执行此操作。因此,作为存储库的实现与域无关,而是与基础架构无关,...
2. 存储库
。另一个存储库不是一个糟糕的选择(在这里你滑入了CQRS区域(。因此,您可以选择更适合读取(缓存(和写入(使用 JPA 进行抽象(的方法。
但是,那么,您真的需要一个用于读取的存储库吗?当读取与写入分开,并且您使用的是两个存储库时,直接访问缓存的服务也将是一种解决方案。最后,您仅在域中使用存储库,当您离开它(读取(时,您可以使用任何您想要的东西来满足您的需求。然后,该服务可以完美地支持UI的需求(或需要列表的地方(。
3. 缓存处理
Id 取决于缓存的处理方式。如果只是通过在请求上添加缓存来完成(列表是通过 ajax 请求加载的,可以缓存(,那么它的超时就足够了,你什么也不必做。
另一方面,如果以另一种方式进行缓存(每个新客户端都会更新的列表(,则需要一个对 ClientCreated 事件做出反应并更新缓存的服务。
第二个选择还需要处理其他事件,如客户端删除等。
CQRS 链接:
https://en.wikipedia.org/wiki/Command%E2%80%93query_separation#Command_query_responsibility_segregation
https://www.slideshare.net/Codemotion/ddd-cqrs-latif?next_slideshow=1
http://cqrs.nu/
https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=92
https://cqrs.files.wordpress.com/2010/11/cqrs_documents.pdf
http://www.h-online.com/developer/features/CQRS-an-architecture-precept-based-on-segregation-of-commands-and-queries-1803276.html
为了尊重 SOLID 原则,在这种情况下,开放闭合原则和 Liskov 替换原则,您只能有一个由repository
和cache
实现的接口IClientsRepository
。这样,您可以随时放下cache
,仅使用repository
,而不会影响系统的正确性;当然,使用缓存会提高性能,但正确性应该是相同的。
因此,您的代码可能如下所示:
public interface IClientsRepository
{
IList<Client> GetClients();
public void UpdateClients(IList<Client> clients);
public void AddClient(Client client);
public void DeleteClient(Client client);
}
public class ClientsRepository : IClientsRepository
{
public IList<Client> GetClients()
{
Get clients from database...
}
}
public class ClientsCache : IClientsRepository
{
private readonly List<Clients> clientsCache;
private readonly IClientsRepository realRepository;
public ClientsCache(IClientsRepository realRepository)
{
this.realRepository = realRepository;
}
public IList<Client> GetClients()
{
if(!clientsCache) {
clientsCache = realRepository.GetClients();
}
return clientsCache;
}
public void UpdateClients(IList<Client> clients)
{
clientsCache = clients;
realRepository.UpdateClients(clients);
}
public void AddClient(Client client)
{
clients.add(client);
realRepository.AddClient(client);
}
public void DeleteClient(Client client)
{
clients.remove(client);
realRepository.remove(client);
}
}
然后,您可以配置首选 DIC 是否使用缓存,无论哪种方式,客户端代码都不会知道或关心。
关于图层,cache
应该与repository
位于同一图层中;在我看来,它们应该位于infrastructure layer
中。