作者:HW-HM
上一篇文章【码手防御-1】防御式编程,我们讨论了防御式编程和契约式设计的概念,本篇将讨论契约式设计六大原则。
契约式设计六大原则。
1、 区分命令和查询。查询返回一个结果,但不改变对象的可见性质。命令改变对象的状态,但不返回结果(应当是不一定返回结果)。
2、 将基本查询同派生查询分开。派生查询可以用基本查询来定义。
3、 针对每个派生查询,设定一个后验条件,使用一个或多个基本查询的结果来定义它。这样我们只要知道基本查询的值,也就能知道派生查询的值。
4、 对于每个命令都撰写一个后验条件,规定每个基本查询的值。结合“用基本查询定义派生查询”的原则,我们现在已经能够知道每个命令的全部可视效果。
5、 对于每个查询和命令,采用一个合适的先验条件。先验条件限定了客户调用查询和命令的时机。
6、 撰写不变式来定义对象的恒定特性。类是某种抽象的体现,应当将注意力集中在最重要的属性上,以帮助读者建立关于类抽象的正确概念模型。
附录一 契约式设计示例
在这个示例中,我们设计了一个简单的集合类。
第一步 我们定义前验和后验表达式:
//前验表达式
#define DbcRequire(condition) /
GetCallStack()->Push((condition),__FILEW__,__FUNCTIONW__,__LINE__);
//后验表达式
#define DbcEnsure(condition) /
GetCallStack()->Push((condition),__FILEW__,__FUNCTIONW__,__LINE__);
第二步 我们根据契约式设计原则,定义我们的集合类:
template<typename T>
class DbcCollection
{
typedef std::vector<T> ElementsType;
public:
//////////////////////////////////////////////////////////////////////////
//创建
inline DbcCollection(void);
inline ~DbcCollection(void);
//////////////////////////////////////////////////////////////////////////
//命令
inline void Add(const T& element);
inline void Insert(int index,const T& element);
inline void Remove(int index);
inline void Update(int index,const T& element);
//////////////////////////////////////////////////////////////////////////
//基本查询
inline const T& Get(int index) const;
inline int GetLength() const;
//////////////////////////////////////////////////////////////////////////
//派生查询
inline bool IsEmpty() const;
inline bool Contains(const T& element);
private:
ElementsType m_elements;
};
第三步 实现集合类,为了简单起见,我们只列出一个方法的实现:
template<typename T>
inline void DbcCollection<T>::Add(const T& element)
{
//前验。通过派生查询Contains,验证此集合不包含新添加的元素
DbcRequire(!m_DbcCollection.Contains(element));
int oldCount = m_DbcCollection.GetLength();
//添加新元素到集合中
m_elements.push_back(element);
//后验。通过基本查询GetLength,验证集合的元素数量增加了1
DbcEnsure(m_DbcCollection.GetLength() == (oldCount+1));
//后验。通过派生查询Contains,验证新元素已经被添加进了集合中
DbcEnsure(m_DbcCollection.Contains(element));
}






































苏公安网备 32011402010933号