Реализация "резервных" классов - PullRequest
5 голосов
/ 15 ноября 2010

У меня есть набор классов, каждый из которых должен в какой-то момент решить, какой из двух или трех подходов они должны использовать внутренне для реализации той же функциональности извне.В идеале это должно включать в себя запасную функциональность, при которой в случае сбоя ApproachA он пробует попробовать ApproachB (и, возможно, подходит к C, D и т. Д.).До сих пор я просто использовал кодирование как if (!success) { ApproachB code }.Проблема заключается в том, что несколько более поздних методов также должны знать, какой подход был выбран, и все они также разрабатывают свои собственные операторы if (MethodChosen) { } else { }.Я действительно хочу решить проблему с помощью чего-то менее громоздкого ... за исключением того, что ни один из других вариантов, которые я рассматривал, не кажется таким "громоздким"Вот три подхода, о которых я подумал:

  1. Реализация статического метода .Create, который решает, какой из двух производных классов создать, где два класса имеют интерфейс, поддерживающий их.Недостатком этого является то, что вы пишете много одного и того же кода дважды, и на самом деле это не создает «запасной вариант», так как заставляет принимать все решения заранее в методе .Create.Это должно сработать 9/10 раз, но в другие 1/10 раза я хочу, чтобы запасной вариант срабатывал только тогда, когда основной попытался и потерпел неудачу.
  2. То же, что и выше, но сзадействован базовый или абстрактный класс, либо в качестве вспомогательного класса для обоих, либо с основным в качестве базового класса для запасного варианта.Это имеет тот же недостаток, что и запасной вариант, но, по крайней мере, мало или нет повторяющегося кода.
  3. Реализация нормально сконструированного абстрактного класса с дочерними классами, которые могут быть изменены во время выполнения: т.е.

    public void SomeMethodOrConstructor()
    {
        if (someConditions)
            MyChild = ChildClassA;
        else
            MyChild = ChildClassB;
    }
    
    
    public void Execute()
    {
        MyChild.Execute();
    }
    

Проблема с вариантом 3 заключается в передаче данных между двумя при необходимости.Поскольку некоторые из этих методов моделируют внешние объекты, это будет довольно часто.Вложенные классы автоматически обмениваются данными со своим родительским классом?Или мне придется передавать все это при каждом вызове?

Что-нибудь еще, что я должен рассмотреть?


Обновление: первый класс запущен и работает с Цепью ответственности.На данный момент я решил не использовать шаблон стратегии или запасной вариант во время выполнения метода, так как считаю, что в конечном итоге он может оказаться ненужным.Я думаю, что большинство таких откатов на выполнение будет на самом деле лучше, если останется в своих собственных классах, так как не будет полного изменения плана игры, всего лишь несколько незначительных изменений, с которыми нужно разобраться.Если окажется, что это не так, я, по крайней мере, знаю, что мне нужно расследовать сейчас.

Спасибо всем, кто помог с окончательным решением!

Для любопытных мойОкончательное решение работало примерно так:

  • Создать абстрактный класс Handler, почти как описано в статье в Википедии, но с функцией public abstract Handler GetHandler() и добавлением других абстрактных методов, таких как Load, Save и т. д.
  • Реализация закрытых подклассов обработчика для родительского класса (они также могут быть подклассами, так как они будут обрабатывать вещи только для этого конкретного класса ... избегая также последующих проблем с именами).Все дочерние классы принимают параметр типа родительского объекта в своем конструкторе, поэтому они имеют легкий доступ к данным родительского объекта.
  • Из конструктора родительского класса настройте обработчики / наследники цепочки ответственности (опять же, простокак в примере), затем вызовите FirstHandler.GetHandler(this) и сохраните результат, чтобы класс знал, какой обработчик использовать в будущем.
  • Большинство обработанных методов затем просто уменьшают до Handler.MethodName().

Ответы [ 3 ]

5 голосов
/ 15 ноября 2010

Использование Цепочка ответственности .

модель цепочки ответственности является шаблон проектирования, состоящий из источника командных объектов и серии обработка объектов. Каждая обработка Объект содержит набор логики, которая описывает типы объектов команд что он может справиться, и как выдать те, что он не может справиться с следующий объект обработки в цепочке. механизм также существует для добавления новых обработка объектов до конца этого цепь.

Это идеально подходит для того, что вам нужно сделать.

1 голос
/ 15 ноября 2010

Я бы, наверное, использовал здесь шаблон стратегии.

http://en.wikipedia.org/wiki/Strategy_pattern

Вам нужно только передать delgates вместо целых классов. Если все методы используют одну и ту же информацию для обработки, это может быть полезно.

0 голосов
/ 15 ноября 2010

Я думаю, вам нужно Task / Task<T>, особенно ContinueWith(Action<Task>) метод и 4 свойства: IsCanceled, IsCompleted, IsFaulted и Result.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...