我正在尝试找到一种优雅的方法来实现决策算法,使其易于维护,因为决策的条件可能会经常变化。
我将尝试在这里举一个更具体的例子:
假设我正试图在一家餐厅的厨房里管理一个厨师团队。
每个厨师都会做3种馅饼:苹果派、南瓜派和覆盆子派,还有2种披萨:芝士披萨和培根披萨。他们都知道怎么做饭。
现在,我想向这些主管下达命令,告诉他们客户会得到什么。
这些条件包括:
头儿一次只能做一个派。例如,如果我命令一个厨师做一个苹果派,我不能命令他做一个覆盆子派或南瓜派,除非苹果派已经做好了,或者我发送了一个取消苹果派的请求。
我可以让一个厨师一次做5个披萨,因为它是为不同的客户准备的。
我想创建一个算法,返回我被允许发送给特定厨师的订单集,关于他已经在做的东西。
我和c++一起工作。我可以写一个简单的switch/case语句,但是如果条件改变或者添加了新的pie,那么维护起来就不容易了,所以...
我有点卡住了,真的看不出我可以如何封装条件和决策,以减少耦合的条件,并允许容易维护的条件,馅饼烹饪。
您将如何处理复杂决策算法实现?
发布于 2014-09-29 17:46:57
我可以写一个简单的switch/case语句,但是如果条件改变或者添加了新的pie,那么维护起来就不容易了,所以...
我有点卡住了,真的看不出我可以如何封装条件和决策,以减少耦合的条件,并允许容易维护的条件,馅饼烹饪。
您将如何处理复杂决策算法实现?
从switch/case到可维护的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
}从维护和可测试性的角度来看,这段代码的可维护性要好得多:
添加新的chef时,客户端代码的
后面形式化(和冻结)
发布于 2014-09-29 18:12:23
不是的。这对于编码来说太多了。只需计算符号即可。这种类型的编码不能保证为"new SweedishChef{}“清除内存释放。并且客户端大小在变量声明中变得更长。
https://stackoverflow.com/questions/26096632
复制相似问题