2014-09-29 8 views
4

Я пытаюсь найти элегантный способ реализовать алгоритм принятия решений, который позволяет легко поддерживать обслуживание, поскольку условия для принятия решений могут часто меняться.Принятие решений, сложные условия и планирование простого обслуживания

Я собираюсь попробовать и быть более конкретным с примером здесь:

Скажем, я пытаюсь управлять командой приготовления пищи шеф-поваров на кухне ресторана.

Каждый шеф-повар знает, как приготовить 3 вида пирогов: яблочный пирог, тыквенный пирог и малиновый пирог и 2 вида пиццы: сырная пицца и беконная пицца. Они все умеют готовить все.

Теперь я хотел бы отправить приказы этим начальникам относительно того, что ждет клиентов.

условия являются:

Вождь может только приготовить один пирог в то время. Если я закажу шеф-повар, чтобы приготовить яблочный пирог, например, я не могу приказать ему приготовить малиновый пирог или тыквенный пирог, если яблочный пирог не будет сделан, или я отправил запрос на отмену яблочного пирога.

Я могу попросить шеф-повара приготовить до 5 пицц одновременно, учитывая, что это для разных клиентов.

Я хотел бы создать алгоритм, который возвращает набор заказов, на которые я могу отправить конкретному шеф-повару, в отношении того, что он уже готовит.

Я работаю с C++. Я мог бы написать простой оператор switch/case, но техническое обслуживание было бы нелегким, если бы условия были изменены или добавлены новые пироги, и поэтому ...

Я немного застрял и действительно не вижу, как я могу инкапсулировать условия и принимать решения, чтобы уменьшить взаимозависимость между условиями и обеспечить удобство обслуживания в условиях приготовления пирога.

Как бы вы справились с внедрением алгоритма принятия решений сложных?

+0

Если его общие проектные решения, которые вы ищете, возможно, что [programers.se] (http://programmers.stackexchange.com/) более подходит для этого вопроса. – Yann

+0

Тогда я переведу свой вопрос, спасибо – JeD

ответ

4

Я мог бы написать простое заявление переключатель/случай, но содержание не будет легко, если условия изменяются или новые пирожки добавляются, а так ...

Я своего рода застрял и действительно не» я вижу, как я могу инкапсулировать условия и принятие решений, чтобы уменьшить сцепление между условиями и обеспечить легкое обслуживание в условиях приготовления пирога.

Как бы вы справились с внедрением алгоритма принятия решений сложных?

Классическое изменение/рефакторинг с помощью переключателя/корпуса на поддерживаемый ООП заключается в замене каждого условия и действия абстрактной классификацией/реализацией класса.

Старый код:

variable_t variable; // initialized elsewhere 
switch(variable) { 
case value1: 
    do_action1(); 
    break; 
case value2: 
    do_action2(); 
    break; 
// ... 
} 

Новый код:

struct Actor // actor is your "abstract chef" 
{ 
    virtual ~Actor(); 
    virtual bool matches(variable_t const v) const = 0; 
    virtual void do_action() = 0; 
}; 

Теперь для каждого действия и комбинации условий, необходимо создать одну специализацию:

struct SweedishChef: public Actor { 
    bool matches(variable_t const v) const override 
    { 
     return v == 1; 
    } 

    void do_action() override 
    { 
     std::cerr << "bork! bork!\n"; 
    } 
}; 

с этим, клиент код больше не имеет ничего жесткого.

Инициализация клиентского кода:

std::vector<std::unique_ptr<Actor>> actors; 
actors.emplace_back(new SweedishChef{} }; 
// adding a new type of chef simply means adding _one_ line of 
// code here, for the new type 

принятия решений (код, заменяющий старый switch код):

// using std::find, begin, end 
variable_t variable; // initialized elsewhere 
const auto chef = find(begin(actors), end(actors), 
    [&v](const std::unique_ptr<Actor>& a) { return a->matches(v); }); 

if(chef != end(actors)) 
    chef->do_action(); 
else 
{ 
    // here goes whatever was in the default part of the switch code 
} 

Из технического обслуживания и тестопригодности точки зрения, этот код намного более ремонтопригодны :

  • Изменения для клиентского кода минимальны при объявлении динг новый повар

  • взаимодействие между поварами и команд были формализованные (и замороженное) за интерфейсом

  • каждое условие/действие может (и должен быть) испытываться отдельно

  • механизм диспетчеризации могут быть протестированы отдельно (и с издеваемыми инъецированными актерами, для удара по различным случаям).

  • механизм инициализации может быть проверен отдельно

+0

Довольно точно, спасибо. Это похоже на шаблон стратегии? – JeD

+1

Этот шаблон называется объектом для государств http://en.wikipedia.org/wiki/State_pattern –

-1

Нет, это слишком много кода. Просто подсчитайте символы. Такой вид кодирования не гарантирует четкого освобождения памяти для «нового SweedishChef {}». И размер клиента стал длиннее в объявлении переменной.

+0

@ user4090727, вопрос конкретно требует дизайна, который уменьшает связь и делает код более модульным/поддерживаемым (не кодом с меньшим количеством символов). Кроме того, «такой тип консолидации» называется RAII (т. Е. Выделяется с помощью «new» и помещает результат в std :: unique_ptr, в std :: vector), и это фактически означает освобождение памяти для «нового SweedishChef {} ». – utnapistim