开放封闭原则,重构

时间:2010-04-22 10:45:42

标签: open-closed-principle

我正在尝试将OCP应用到我所拥有的代码片段中,当前的状态真的很臭,但我觉得我没有一路走到最后。

当前代码:

public abstract class SomeObject
{}

public class SpecificObject1 : SomeObject
{}

public class SpecificObject2 : SomeObject
{}


// Smelly code
public class Model
{
  public void Store(SomeObject someObject)
  {
    if (someObject is SpecificObject1)
    {}
    else if (someObject is SpecificObject2)
    {}
  }
}

这真的很难看,我的新方法看起来像这样:

// No so smelly code
public class Model
{
  public void Store(SomeObject someObject)
  {
    throw new Expception("Not allowed!");
  }

  public void Store(SpecificObject1 someObject)
  {}

  public void Store(SpecificObject2 someObject)
  {}

}

当出现新的SomeObject类型时,我必须实现该特定对象的方式 存储,这将打破OCP因为我需要改变Model类。

将商店逻辑移动到SomeObject也感觉不对,因为我会违反SRP(?),因为在这种情况下,SomeObject几乎就像一个DTO,它的重要性不是如何知道存储自己。

如果SomeObject的新实现出现了缺少哪个商店实现 由于Model类中的Store方法异常,我会得到运行时错误,它也感觉像代码味道。

这是因为调用代码将采用

的形式
IEnumerable<SomeObject> sequence;

我不知道序列对象的具体类型。

我似乎无法掌握OCP概念。任何人都有任何具体的例子或链接,而不仅仅是一些汽车/水果的例子?

1 个答案:

答案 0 :(得分:1)

我提出的模式试图为特定对象注册处理程序。必须为可能发生的每种类型的对象注册处理程序。如果没有处理程序可以处理它,则抛出异常。

您可以从您或其他程序集动态加载处理程序(实现IHandler的所有内容)并实例化并添加注册它们。因此,为任何类型创建处理程序类就足够了实现SomeObject

public interface IHandler {
    bool TryHandle (SomeObject o); // return true iff handled
}

public class Model
{
    private List<SIandler> _Handlers = new List<IHandlers>();

    // registers a new handler
    public void RegisterHandler (IHandler h) {
        _Handlers.Add(h);
    }

    // this tries to store an object by letting all handlers attempts to store
    public void Store (SomeObject o) {
        foreach (var h in _Handlers) {
            if (h.Store(o)) return;
        }

        // no handler was able to handle the type
        throw new Exception();
    }
}

public class Specific1Handler: IHandler
{
    public bool Handle (SomeObject o) {
        if (o is SpecificType1) {
            /* store... */
            return true; // we handled this object
        } else {
            // we're not qualified
            return false;
        }
    }
}

我相信这符合您的需求。 (顺便说一下,我不知道这个模式是否有名字,如果有的话会很高兴。)