接口继承 - 如何不破解Liskov替换原则和单一责任模式?

时间:2014-03-26 07:55:24

标签: c# design-patterns inheritance liskov-substitution-principle

我有一个通用的存储库模式,我现在看到我需要一个自定义方法来实现这个模式的一个特定实现,让我们调用实现CustomerRepository和方法GetNextAvailableCustomerNumber。我有一些想法,但它们不符合面向对象设计的SOLID原则。

我首先考虑为该实现创建一个自定义存储库模式(ICustomerRepository),但这实际上并不可行。经验告诉我,还有一些其他方式,我目前尚未考虑或甚至不知道。此外,我不认为为道路上的每一个碰撞发明一个新的存储库接口都应该这么做。

然后我考虑让ICustomerRepository继承IRepository< Customer>并且只需为GetNextAvailableCustomer添加方法签名,但这与Liskov的替换原则非常相似,我相信它对单一责任模式的影响也很小。我仍然能够实现基于IRepository的客户存储库,即使我只想使用ICustomerRepository。我最终会得到两个替代方案,而且客户端应该实现哪个接口将不再明显。在这种情况下,我希望它只能实现ICustomerRepository,而不是IRepository< Customer>

这是什么方法?接口继承真的是要走的路,或者是否有任何其他理想的方法可以符合LSP?

这是我的通用存储库界面:

public interface IRepository<T>
    where T : IEntity
{
    T GetById(int id);

    IList<T> GetAll();

    IEnumerable<T> Query(Func<T, bool> filter);

    int Add(T entity);

    void Remove(T entity);

    void Update(T entity);
}

3 个答案:

答案 0 :(得分:4)

你实际上没有打破Liskov的替代原则。利斯科夫说

  

程序中的对象应该可以替换为它们的实例   子类型而不改变该程序的正确性

在你的情况下,你可以。根据您对Liskov的解释,几乎不允许继承和扩展类。

我认为ICustomerRepository&#34; inherents&#34;来自IRepository会很好。我仍然可以在任何地方替换ICustomerRepository我将使用IRepostory(给定ICustomerRepository:IRepostory)

Liskov防范子类的意外行为。最常用的(虽然不一定是最好的)例子似乎是一个正方形从矩形中得到的例子。这里我们有一个被Square覆盖的SetWidth方法,但是Square也设置了高度,因为它是一个正方形。因此,原始方法定义在子类中更改,因此违反了原则。

答案 1 :(得分:1)

你不会破坏LSP。

Subtypes must be substitutable for their base types.(来自Agile.Principles.Patterns。和实践中的LSP#[Robert.C.Martin]一书)

如果将新方法GetNextAvailableCustomer添加到ICustomerRepository,它仍然可以被IRepository替代。

以下是存储库模式Entity Framework, Repository and Specification Pattern

的好文章

source code for different .net versions

答案 2 :(得分:1)

利斯科夫并不打算取消延长计划的任何手段。替换原则是关于用子类型替换基类型时程序的正确性。

向子类型添加其他方法是完全有效的:任何需要基本类型的地方知道也不会使用其他方法。如果用子类替换那些位置中使用的实现,代码中的那些位置仍然可以正常工作。

打破LSP的一个例子是,如果你创建一个实现,当你调用&#34; Query&#34;或者&#34;删除&#34;方法添加一个元素和&#34;添加&#34;方法删除元素。

据我所知,创建一个继承自ICustomerRepository的{​​{1}}并添加客户特定的方法正是存储库模式的含义。