我有一个后期操作api。我们正在使用C#,并为每个层(Api,业务逻辑,数据访问)提供单独的程序集
此操作必须与多个数据源进行交互。
我们经常使用服务(用于逻辑)和存储库进行数据访问。
选项1
优势在于所有逻辑都在服务中,并且感觉更加“单一责任”。这样做的缺点是,以后有人可以直接使用“datasource 1 repository”并插入记录,而不知道它也应该插入到数据源2中。
选项2 创建一个单独的存储库,使用一个与两个数据源交互的get和insert操作。这样可以确保您不会在没有其他人的情况下与其他人互动,但会感觉不到“单一责任”。
选项3 有3个存储库......
公共存储库可以使用2个“特定于数据源”的存储库并遵循上面的逻辑。这将逻辑从服务转移到存储库,但具有以下优点:实现对数据层之外的任何人都是隐藏的。
人们的想法是什么?这有设计模式吗?
答案 0 :(得分:0)
这个要求感觉很像Chain of Responsibility Pattern,遗憾的是,它不会为减少数据访问代码量做很多事情。我很想读一个符合读者水平的读者。在检查中,让它们都实现一些通用的接口,并使用一个责任链(即我可以处理这个,如果没有请求链中的下一个对象)来执行操作。您可以将链中的每个项目设为迷你存储库,或者根据需要使用其他存储库。
如果你已经在结构中拥有它们,或者在其他地方需要类似的读者,可能只会担心特定的存储库。
答案 1 :(得分:0)
答案 2 :(得分:0)
一方面,我可以为每个数据源创建一个存储库,每个数据源都有一个get操作和一个insert操作。然后我可以创建一个遵循上述逻辑的服务。
优势在于所有逻辑都在服务中,并且感觉更加“单一责任”。
我也喜欢这个选项,如果我是你,我会选择这个选项。
另一种选择是创建单个存储库,使用单个插入操作与两个数据源进行交互。这样可以确保您不会在没有其他人的情况下与其他人互动,但会感觉不到“单一责任”。
我不喜欢将数据源检查放在一个仓库中的选项,因为这听起来像是服务层的责任。
另一种选择是拥有3个存储库。 1是公共的,由服务(DDD)使用,并且此存储库与仅内部的数据源特定存储库进行通信。
我不确定你的内心是什么意思。如果在内部你的意思是internal
,就像在程序集中一样,它仍然有与前一个选项相同的缺点。
关于第一个选项,我和你喜欢,你这样说:
这样做的缺点是有人可以在以后轻松地使用“数据源1存储库”直接插入记录而不知道它应该插入到数据源2中。
我们可以做些什么来避免这种情况。创建一个这样的类,并想象我们正在保存Customer
:
public class Customer { }
public class CustomerData
{
public string MyProperty { get; private set; }
private CustomerData()
{
}
public Customer Customer { get; private set; }
// or not void
public static void Save(Customer customer)
{
// Check all datasources and save wherever you need to
// obviously through injection or whatever. I will just
// new-it up here
var cd = new CustomerData { Customer = customer };
var repo1 = new CustomerRepository();
repo1.Save(cd);
bool someCondition = true;
if (someCondition)
{
var repo2 = new CustomerRepository();
repo2.Save(cd);
}
}
}
请注意构造函数是私有的,因此开发人员无法创建它。现在像这样创建您的存储库:
public class CustomerRepository
{
public void Save(CustomerData cd) { // Save cd.Customer to datasource }
}
请注意,它需要CustomerData
作为参数。
OK!所以让我们使用repo:
var repo = new CustomerRepository();
// Oops cannot create CustomerData.
// repo has no other method except for CustomerData.
repo.Save(new CustomerData());
// There is no other way except for this or the developer has to add
// a method to the repo-but what can we do about that, not much!
CustomerData.Save(new Customer());
答案 3 :(得分:0)
从我所看到的界面就像persistSomethingToRepository
。此接口是所有客户端代码关心的。它并不关心您使用辅助遗留系统的事实(也不应该)。这种观察很大程度上简化了实现,因为您可以使用Decorator pattern来装饰DataSource1,同时保持对DataSource2的持久性。
我没有足够的C#经验,但伪OOP代码是这样的:
interface Repository {
void persistSomething(something);
}
class Source1 implements Repository {
void persistSomething(something) {
// insert into database
}
}
class Source2AndSource1 implements Repository {
// inject the right database connection and a Source1 instance
void persistSomething(something) {
// Check if the data already exists in datasource 1
// If it doesn't exist in datasource 1, check if the data already exists in datasource 2
//If it doesn't exist in datasource 2, insert it in to datasource 1 and then insert it in to datasource 2
}
}
然后,只需配置您的依赖注入容器(DIC),以便在需要Source2AndSource1
时使用Repository
的实例。
当您的旧系统(源2)不再使用时,您只需将DIC配置为使用Source1
而不是Source2AndSource1
的实例,而无需对客户端代码进行任何修改。这会为您提供SOLID代码,更准确地说是Open/closed Principle和Single responsibility principle。