我认为,使用示例更容易解释.让我们来一个模拟一级方程式赛车速度的课程,界面可能如下所示:
class SpeedF1
{
public:
  explicit SpeedF1(double speed);
  double getSpeed() const;
  void setSpeed(double newSpeed);
  //other stuff as unit 
private:
  double speed_;
};
现在,负速度在这种特殊情况下没有意义,也没有超过500 km/h的值.在这种情况下,如果提供的值不在逻辑范围内,则构造函数和setSpeed函数可能会抛出异常.
我可以引入一个额外的抽象层并插入一个额外的对象而不是double.新对象将是double的包装器,它将构造并永不修改.该类的接口将更改为:
class ReasonableSpeed
{
public:
  explicit ReasonableSpeed(double speed); //may throw a logic error
  double getSpeed() const;
  //no setter are provide
private:
  double speed_;
};
class SpeedF1
{
public:
  explicit SpeedF1(const ReasonableSpeed& speed);
  ReasonableSpeed getSpeed() const;
  void setSpeed(const ReasonableSpeed& newSpeed);
  //other stuff as unit 
private:
  ReasonableSpeed speed_;
};
使用这种设计SpeedF1不能抛出,但是每次我想重置速度时我需要额外支付一个对象构造函数.
对于有限的一组值是合理的类(例如日历中的月),我通常将构造函数设为私有,并提供一组完整的静态函数.在这种情况下,这是不可能的,另一种可能性是实现一个空对象模式,但我不确定它是否优于简单抛出异常.
最后,我的问题是:
解决此类问题的最佳做法是什么?
首先,不要高估额外构造函数的成本.实际上,这个成本应该是初始化double加上有效性检查成本的成本.换句话说,它可能等于使用原始double.
其次,失去了二传手.塞特斯 - 以及在较小程度上,吸气者 - 几乎总是反模式.如果你需要设置一个新的(最大)速度,你可能真的想要一辆新车.
现在,关于实际问题:投掷构造函数原则上完全没问题.不要编写复杂的代码来避免这样的构造.
另一方面,我也喜欢自我检查类型的想法.这充分利用了C++的类型系统,我全都赞成这一点.
两种选择都有其优点.哪一个最好取决于具体情况.一般来说,我尝试尽可能地利用类型系统和静态类型检查.在你的情况下,这意味着有一个额外的速度类型.
| 归档时间: | 
 | 
| 查看次数: | 200 次 | 
| 最近记录: |