这会违反开放/封闭原则吗?

时间:2015-01-21 22:45:06

标签: c# oop solid-principles open-closed-principle

我下午大部分时间都在阅读开放/封闭原则,而我似乎无法理解它。 以下是我已经阅读的一些参考文章,似乎我错过了一些东西。

  1. Understanding the Open Closed Principle
  2. The end of dependency injection - who creates the dependencies?
  3. 假设我有一个基础通用存储库,它公开了一些最通用的方法,可以满足存储库的任何需求。

    存储库

    public abstract class Repository<TModel> where TModel : class {
        protected Repository() { }
    
        public abstract IList<TModel> FilterBy(
            Expression<Func<TModel, bool>> filterExpression);
        public abstract IList<TModel> GetAll();
        public abstract TModel GetById(int id);
        public abstract Save(TModel instance);
    }
    

    然后,我希望专注于ProductRepository。

    ProductRepository

    public abstract class ProductRepository : Repository<Product> {
        protected ProductRepository() : base() { }
    }
    

    让我们假设我从基础存储库中获得了所有我需要的东西。如果是这样,那么我觉得我没有打破开放/封闭原则,因为我没有定义任何新成员等。

    但是,我是否需要一种特殊的存储库,比如说一个AlertLevelConfigurationRepository,业务需求说明我一次只能有一个AlertLevelConfiguration。因此,存储库需要始终获取当前配置。

    AlertLevelConfigurationRepository

    public abstract class AlertLevelConfigurationRepository 
        : Repository<AlertLevelConfiguration> {
        protected AlertLevelConfigurationRepository() : base() { }
    
        public abstract AlertLevelConfiguration GetCurrent();
    } 
    

    现在,由于这个新方法,我觉得我打破了开放/封闭原则,因为这个类是来自其祖先的修改后的派生类型。它被修改,因为存储库的基本定义不提供此GetCurrent方法。此外,我非常确定我永远不会使用任何基本方法,除了Save方法,因为更改级别配置可以是可配置的!

    最后,我想知道我是否理解开放/封闭原则,不知何故我怀疑我这样做。

    我想知道这是否是一个原则被打破的例子,如果没有,那么我想对原则本身做一些解释。

1 个答案:

答案 0 :(得分:3)

你有什么看起来像“开放/封闭原则”的定义 - Repository类是开放的扩展,但是关闭到修改。您可以通过扩展它(以新的子类的形式)添加新功能,而无需修改Repository类。将GetCurrent()调用添加到Alert子类是该原则的“Open to extension”部分。

打开/关闭是关于特定类是打开/关闭,而不是整个继承层次结构。你想写一次这个类,只是因为一个原因改变它(单一责任原则)。

你提出了一个单独的问题:

“此外,我很确定除了Save方法之外我永远不会使用任何基本方法,因为alter level配置可以是可配置的!”

这是设计不良的继承层次结构的标志,或者选择从不正确的类继承。如果您继承了许多您不需要或不想使用的功能,那么它就不是正确的基类,或者该类做得太多(违反单一责任原则)。

您可能想要的是将一些此功能(例如您的Alert类不需要的GetAll()GetById()调用)封装到仅包含需要该功能的派生类的单独类中将作为依赖关系(假设您正在使用DI)。或者可能将该功能放入一个派生自Repository的类中,并且需要从该类派生的类(尽管我更喜欢使用Composition解决方案而不是继承解决方案)。