因此。这可能是一个愚蠢的问题,但是......
我仅限于使用不支持EntityFramework的数据库,但我仍然想将我的数据层分离到一个单独的程序集中。这意味着我需要共享域对象值,同时避免业务和数据层之间的循环引用。因此,我想知道构建一个可以由业务层实现并相互独立地传递给数据层的持久性接口存储库是否可以接受。
示例如下:
// Business Layer
public class Customer: IPersistableCustomer
{
private string name;
public string Name{ get { return this.name; } }
public void persist()
{
dataLayer.StoreCustomerInstance(this);
}
}
// DataLayer
public StoreCustomerInstance(IPersistableCustomer persistableCustomer)
{
// Do storage stuff
}
// Interface repository
public interface IPersistableCustomer
{
string Name { get; }
}
我几乎可以肯定这是一个可怕的想法,但我不确定为什么。我有兴趣知道人们的想法,看看可能存在哪些潜在的陷阱。
答案 0 :(得分:6)
您在示例中所做的是隐藏界面背后的域对象。您应该做的是将数据层隐藏在接口后面。这种数据层抽象通常称为存储库模式。
在业务层中,您可以定义域类和存储库接口:
public class Customer
{
public Customer(string name)
{
this.Name = name;
}
public string Name { get; private set; }
}
public interface ICustomerRepository
{
void Save(Customer customer);
}
请注意,Customer类没有任何持久性逻辑。存储库接口也没有;它只定义数据层的契约。
合同的实施在数据层中进行:
public class SqlCustomerRepository : ICustomerRepository
{
public void Save(Customer customer)
{
// Persistence logic
}
}
此时,数据层需要对业务层的引用,但不是相反。
您可以在应用程序层中将这两个层绑定在一起:
class CustomerForm
{
private readonly ICustomerRepository customerRepository;
// This class declares a dependency on any ICustomerRepository
public CustomerForm(ICustomerRepository customerRepository)
{
this.customerRepository = customerRepository;
}
public void PersistCustomer()
{
Customer customer = CreateCustomerFromUserInput();
this.customerRepository.Save(customer);
}
}
class Program
{
static void Main(string[] args)
{
// Dependency injection, usually done via a DI container
var customerRepository = new SqlCustomerRepository();
var form = new CustomerForm(customerRepository);
form.PersistCustomer();
}
}
我发现Onion Architecture上的文章在遇到与您相同的问题时非常有价值。它解释了如何以防止与数据层紧密耦合的方式设置应用程序的体系结构。
使用数据层接口的另一个优点是,它允许您对大部分代码进行单元测试,而无需运行实际的数据库。您只需模拟存储库接口即可。
几年前我曾经为我的域对象使用过接口。我不后悔,因为它告诉我不如何做到这一点。但这是唯一的好事;这是一项额外的工作和维护,没有任何实际好处:)