Открытый закрытый принцип, рефакторинг - PullRequest
2 голосов
/ 22 апреля 2010

Я пытаюсь применить 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, потому что мне нужно изменить класс модели.

Чтобы переместить логику хранилища в SomeObject, он также чувствует себя неправильно, тогда я нарушу SRP (?), Потому что в этом случае SomeObject почти как DTO, его ответственность - это не то, как знать, как хранить себя.

Если появляется новая реализация SomeObject, чья реализация магазина отсутствует Я получу ошибку runtime из-за исключительной ситуации в методе Store в классе Model, он также напоминает запах кода.

Это потому, что вызывающий код будет иметь вид

IEnumerable<SomeObject> sequence;

Я не буду знать конкретные типы объектов последовательности.

Не могу понять концепцию OCP. У кого-нибудь есть конкретные примеры или ссылки, которые немного больше, чем просто пример Car / Fruit?

1 Ответ

1 голос
/ 22 апреля 2010

Шаблон, который я представляю, пытается зарегистрировать обработчики для определенных объектов. Должен быть зарегистрирован обработчик для каждого типа объекта, который может произойти. Если никакой обработчик не может справиться с этим, выдается исключение.

Вы можете загружать обработчики (все, что реализует 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;
        }
    }
}

Я полагаю, что это будет соответствовать вашим потребностям. (Кстати, я не знаю, есть ли у этого шаблона имя, буду рад узнать, есть ли оно.)

...