决策,复杂的条件和规划易于维护

时间:2014-09-29 09:28:45

标签: c++ maintenance design-decisions

我试图找到一种优雅的方法来实施一种易于维护的决策算法,因为决策的条件可能经常发生变化。

我将尝试通过此处的示例进行更具体的说明:

让我们说我正试图在餐厅厨房里管理一个烹饪厨师团队。

每位厨师都知道如何烹制3种馅饼:苹果派,南瓜派和覆盆子派以及2种披萨:芝士披萨和培根披萨。他们都知道如何做饭。

现在,我想向这些负责人发出关于客户即将到来的命令。

条件是:

酋长一次只能做一个馅饼。如果我点一个厨师做一个苹果派,我不能命令他做一个覆盆子派或南瓜派,除非苹果派完成或我发送取消申请苹果派。

我可以要求厨师一次最多烹饪5个比萨饼,这是为了不同的客户。

我想创建一个算法,该算法返回我允许发送给特定厨师的订单集,关于他已经在做什么。

我正在使用c ++。 我可以写一个简单的开关/ case语句,但是如果条件改变或添加了新的pies,那么维护就不容易了......所以...

我有点陷入困境,并且真的不知道如何将条件和决策封装起来以减少条件之间的联系,并且可以轻松维持馅饼烹饪的条件。

您将如何处理复杂的决策算法实现?

2 个答案:

答案 0 :(得分:4)

  

我可以写一个简单的开关/案例陈述,但如果条件改变或添加了新的馅饼,维护将不容易,所以...

     

我有点陷入困境,实际上并没有看到如何将条件和决策封装起来以减少条件之间的联系,并且可以方便地维持馅饼烹饪的条件。

     

您将如何处理复杂的决策算法实现?

从交换机/案例到可维护OOP的经典更改/重构是用抽象类专门化/实现替换每个条件和操作。

旧代码:

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
}

从维护和可测试性的角度来看,此代码更易于维护:

  • 添加新厨师

  • 时客户端代码的更改很少
  • 厨师和命令之间的互动已在界面背后正式化(并冻结)

  • 每个条件/行动可以(并且应该)单独测试

  • 调度机制可以单独测试(以及模拟注入的演员,用于击中各种情况)。

  • 初始化机制可以单独测试

答案 1 :(得分:-1)

没有。代码太多了。只计算符号。这种编码并不能保证“new SweedishChef {}”可以清除内存。并且变量声明中的客户端规模变得更长。