c++设计选择
C++ design choice
有一个类ActionSelection,它有以下方法:
ActionBase* SelectAction(Table* Table, State* State);ActionBase是一个抽象类。在SelectAction方法内部,如果表不是空的,则考虑状态,从表中获取一些动作。
如果表为空,则应该创建并返回一个随机操作。但是ActionBase是一个抽象类,所以不能被实例化
对于不同的实验/环境,动作是不同的,但有一些共同的行为(这就是为什么有一个ActionBase类)
问题是,这个函数(SelectAction)应该返回一个实验特定的动作,如果表是空的,但是它不知道任何关于特定的实验。有什么设计上的变通方法吗?
这取决于空表是否…
- 预计在正常情况下发生
- 可能在异常情况下发生
- 应该永远不会发生,除非程序中有错误
解决方案1:
在控制流中包含空表处理。函数没有足够的信息来正确响应,因此:
-
传入第三个参数,包含要返回的默认操作:
ActionBase *SelectAction(Table *table, State *state, ActionBase *defaultAction);
如果你不想构造默认的动作,除非它是必要的,你可以通过模板参数传递它的类型,可以选择使用附加的参数来构造它:
template <class DefaultAction, class... DefActArgs> ActionBase *SelectAction(Table *table, State *state, DefActArgs &&... args);
-
让调用者处理它,返回操作是否成功:
bool SelectAction(Table *table, State *state, ActionBase *&selectedAction);
解决方案2:
抛出异常。谁能处理它,它就会冒出来。这很少用作参数检查,因为它应该由首先应该产生非空表的对象抛出。
ActionBase *SelectAction(Table *table, State *state) {
if(table->empty())
throw EmptyTableException();
// ...
}
解决方案3:
设置断言。如果你的函数收到一个空表,说明有问题,最好停止程序,用调试器检查一下。
ActionBase *SelectAction(Table *table, State *state) {
assert(!table->empty());
// ...
}
这是我的想法:这不是经过测试的代码,但是你明白了。
1 .
//header
class RandomActionBase : public ActionBase{
public
RandomActionBase();
static RandomAction* selectRandomAction();
protected:
static RandomActionBase* _first;
RandomActionBase* _next;
void register(RandomActionBase* r);
};
//implementation
RandomActionBase::_first = NULL;
RandomActionBase::RandomActionBase():_next(NULL){
if (_first==NULL) _first = this;
else _first->register(this);
}
void RandomActionBase::register(RandomActionBase* r)
{
if (_next==NULL) _next = r;
else _next->register(r);
}
RandomAction* RandomActionBase::selectRandomAction()
{
//count the number of randomactionbases
int count = 0;
RandomActionBase* p = _first;
while(p){
++count;
p = p->_next;
}
//now that you know the count you can create a random number ranging from 0 to count, I 'll leave this up to you and assume the random number is simply 2,
unsigned int randomnbr = 2;
RandomActionBase* p = _first;
while(randomnbr>0){
p= p->_next;
--randomnbr;
}
return p;
}
//header
class SomeRandomAction : public RandomActionBase{
public:
//implement the custom somerandomaction
}
//implementation
static SomeRandomAction SomeRandomAction_l;
当然,我们的想法是创建SomeRandomAction的不同实现,甚至通过构造函数将参数传递给它们,使它们完全不同。对于您创建的每个实例,它们都将出现在静态列表中。用新的实现扩展列表只是意味着从RandomActionBase派生,实现它并确保创建一个实例,基类永远不会受此影响,这使得它甚至是根据OCP设计的。开闭原则。代码是可扩展的,而不必更改已经存在的代码。OCP是SOLID的一部分。
2。另一个可行的解决方案是返回一个空对象。它与上面非常相似,但是当列表为空时,您总是返回null对象。请注意,空对象并不仅仅是空。参见https://en.wikipedia.org/wiki/Null_Object_pattern它只是一个类的虚拟实现,以避免必须检查空指针,从而使设计更优雅,更不容易受到空指针解引用错误的影响。
相关文章:
- 如何使用默认参数等选择模板专业化
- 如何(从固定列表中)选择一个数字序列,该序列将与目标数字相加
- 选择要调用的构造函数
- C++选择排序算法中的逻辑错误
- QTreeView幻灯片多选后无法使用单击选择
- 无法获取菜单选择以运行函数.C++
- Qt C++静态thread_local QNetworkAccessManager是线程应用程序的好选择吗
- 在C++中,如何通过几种类型从元组中选择多个元素
- 讨论 - 创建矩阵时的数组与向量的向量 - 什么是最实用的选择
- 对可变参数使用声明.如何选择正确的功能
- 选择选举获胜者的程序
- 如何选择在 csv 文件中输出的位置
- 根据用户回答声明"Players"。用户选择玩家数量。播放器是结构体
- 程序在尝试猜测它选择的随机数时进入无限循环?
- 选择和修改嵌套向量中的条目的最佳实践
- 在PostgreSQL中根据它们的ID选择大量行的最快方法是什么?
- 表达式 SFINAE:如何根据类型是否包含具有一个或多个参数的函数来选择模板版本
- 在运行时选择父类的实现
- 数数并选择 sqlite 中的前三名
- 列表视图更改选择颜色