【问题标题】:Is it acceptable to use interfaces to pass data to the data layer使用接口将数据传递给数据层是否可以接受
【发布时间】:2013-12-13 12:45:14
【问题描述】:

所以。这可能是个愚蠢的问题,但是...

我仅限于使用不支持 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; }
}

我几乎可以肯定这是一个糟糕的主意,但我不知道为什么。我很想知道人们的想法,看看可能存在哪些潜在陷阱。

【问题讨论】:

    标签: c# object domain-driven-design


    【解决方案1】:

    您在示例中所做的是将域对象隐藏在界面后面。您应该做的是将数据层隐藏在接口后面。这种数据层的抽象通常称为存储库模式

    在业务层中,您定义域类和存储库接口:

    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 上的文章非常有价值。它解释了如何以防止与数据层紧密耦合的方式设置应用程序的架构。

    为数据层使用接口的另一个优点是,它允许您对大部分代码进行单元测试,而无需运行实际的数据库。您可以简单地模拟存储库接口。

    几年前我曾经为我的领域对象使用过接口。我不后悔,因为它教会了我如何去做。但这是唯一的好处;这是很多额外的工作和维护,没有任何真正的好处:)

    【讨论】:

    • 我不同意“此时数据层需要对业务层的引用”,因为如果您在哪里垂直绘制图层,您的数据在底部,业务在顶部数据。从架构的角度来看,这与您所需要的相反。你打电话,你从来不打电话,业务比数据更不稳定,业务应该调用数据。
    猜你喜欢
    • 2016-11-20
    • 1970-01-01
    • 2010-10-13
    • 2017-04-12
    • 1970-01-01
    • 2019-01-21
    • 2011-08-23
    • 2019-12-16
    • 1970-01-01
    相关资源
    最近更新 更多