用 NVI 模式来实现契约的前置条件、后置条件和不变式
黄国强 2009-9-25
参考书[1]中的“简单栈”的例子是用 Eiffel 语言写的。
下面的例子是我在C++中用 NVI 模式[2]来实现契约的前置条件、后置条件和不变式。
// 负责表示一个简单的栈
template<class T>
class CSimpleStack
{
public:
virtual ~CSimpleStack(void){}
// 基本查询: 栈中元素数目
int Count(void)const
{
return DoCount();
}
// 基本查询: 逻辑位置为i的元素,栈顶逻辑位置是Count()-1
T ItemAt(int i)const
{
ASSERT(i>=0 && i<Count()); // 前置条件
T ret = DoItemAt(i);
return ret;
}
// 派生查询: 栈是否为空
bool IsEmpty(void)const
{
bool ret = DoIsEmpty();
ASSERT(ret == (Count()==0)); // 后置条件
return ret;
}
// 派生查询: 查询栈顶元素
T Item(void)
{
ASSERT(Count()>0); // 前置条件
T ret = DoItem();
ASSERT(ret == ItemAt(Count()-1); // 后置条件
return ret;
}
// 创建命令: 初始化
void Init(void)
{
DoInit();
ASSERT(Count()==0); // 后置条件
}
// 其他命令: 将t压入栈顶
void Put(T t)
{
int nOldCount = Count();
DoPut();
ASSERT(Count()==nOldCount+1); // 后置条件
ASSERT(ItemAt(Count()-1) == t); // 后置条件
ASSERT(Invariant()); // 不变式
}
// 其他命令: 移除栈顶元素
void Remove(void)
{
ASSERT(Count()>0); // 前置条件
int nOldCount = Count();
DoRemove();
ASSERT(Count()==nOldCount-1); // 后置条件
ASSERT(Invariant()); // 不变式
}
// 不变式
bool Invariant(void)
{
return Count()>=0;
}
private:
virtual int DoCount(void)const = 0;
virtual T DoItemAt(int i)const = 0;
virtual bool IsEmpty(void)const = 0;
virtual T DoItem(void)const = 0;
virtual T DoInit(void) = 0;
virtual void DoPut(void) = 0;
virtual void DoRemove(void) = 0;
};
按契约式设计,上面的这段代码带来很多好处,简单枚举一下:
1 自释义,写继承类的人可以很清楚自己需要达到的目标;
2 自动验证,不正确的实现很容易暴露出来;
3 减少了单元测试的工作。
[参考]
1 Design by Contract,by Example Richard Mitchell,Jim McKim,Addison-Wesley
中文版 Design by Contract 原则与实践 Richard Mitchell,Jim McKim 译者:孟岩 人民邮电出版社
2 http://acloudblog.blog.sohu.com/129992469.html
用 NVI 模式来实现契约的前置条件、后置条件和不变式
最新推荐文章于 2023-12-16 21:00:20 发布