求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
  
 
 
     
   
分享到
基于接口四种C++编程思想的实例分析
 
作者 java是一门好语言,火龙果软件    发布于 2013-12-12
 

版本1:结构化的思想

需要实现一个加法器:在这个加法器中,已经保存了被加数;现在需要传递加数给这个加法器,以让其返回加法计算结果。
结构化的基本思路:用一个结构体来保存被加数,然后再外带一个加法函数

#include <iostream>
using namespace std;
struct SLAugend
{
int iAugend;
};
int Add(struct SLAugend *pSLAugend, int iAddend)
{
return pSLAugend->iAugend + iAddend;
}
int main()
{
struct SLAugend augend;

augend.iAugend = 2;

cout << Add(&augend, 5) << endl;
return 0;
}

SL:就是结构体的缩写 Augend 是被加数的英文 Addend 是加数的英文 i是 int 的缩写 p 是指针的缩写

老师采用了匈牙利编码方式

变化来了:现在需要给被加数添加一个权重值;但是以前的加法器仍需保留,因为还有一部分代码会使用它。

思路:

既然还有一部分代码要用老的加法器,那么老加法器我们还是要保留的

按照原有思路开发新的加法器

#include <iostream>
using namespace std;
struct SLAugend
{
int iAugend;
};
int Add(struct SLAugend *pSLAugend, int iAddend)
{
return pSLAugend->iAugend + iAddend;
}
struct SLWeightingAugend
{
int iAugend;
int iWeight;
};
int WeightingAdd(struct SLWeightingAugend *pSLWeightingAugend, int iAddend)
{
return pSLWeightingAugend->iWeight * pSLWeightingAugend->iAugend + iAddend;
}
int main()
{
struct SLWeightingAugend augend;

augend.iAugend = 2;
augend.iWeight = 3;

cout << WeightingAdd(&augend, 5) << endl;
return 0;
}

为什么会有如此长的变量名?

反对写注释!!!

不少人的注释写得很无聊,如“定义了一个整型变量”。这种情况主要为了应付检查

很多时候代码和注释不一致——赶进度

不写注释能看懂代码吗?

按照职责单一的原则,这将导致每个类都很小

通常至多200到300行,再加上每个类对应.h和.cpp文件,因此不会出现一个文件上千行而不知从何处下手

反对写注释!!!

不写注释能看懂代码吗?

按照职责单一的原则,这将导致每个类都很小

变量、函数、类的名称通常都较长,能起到顾名思义的作用——代码自注释

eightingAdd、SLWeightingAugend、 pSLWeightingAugend

文档还是要写的

重要的类需要总体性的说明

复杂的算法需要说明

类之间的关系需要说明

版本1的缺陷

加法器没有把被加数、权重,以及操纵它们的加法运算封装在一起(封装性 是面向对象的基本特性之一)

当引入带权重的加法器时,需要对部分老代码进行修改,没有做到代码的封闭性

没有实现变化点的封装

版本2:基于对象的思想

需要实现一个加法器:在这个加法器中,已经保存了被加数;现在需要传递加数给这个加法器,以让其返回加法计算结果。
思路:编写一个加法器的类,用一个数据成员保存被加数,然后再写一个public的加法方法

#include <iostream>
using namespace std;
class CLAdder
{
public:
explicit CLAdder(int iAugend)
{
m_iAugend = iAugend;
}
int Add(int iAddend)
{
return m_iAugend + iAddend;
}
private:
int m_iAugend;
};
int main()
{
CLAdder adder(2);
cout << adder.Add(4) << endl;

return 0;
}

m_指的是成员变量

基于对象的思想

变化来了:现在需要给被加数添加一个权重值;但是以前的加法器仍需保留,因为还有一部分代码会使用它。

思路:

既然还有一部分代码要用老的加法器,那么老加法器我们还是要保留的

按照原有思路开发新的加法器CLWeightingAdder

基于对象的思想

变化来了:现在需要给被加数添加一个权重值;但是以前的加法器仍需保留,因为还有一部分代码会使用它。

思路:

既然还有一部分代码要用老的加法器,那么老加法器我们还是要保留的

按照原有思路开发新的加法器CLWeightingAdder

基于对象的思想

变化来了:现在需要给被加数添加一个权重值;但是以前的加法器仍需保留,因为还有一部分代码会使用它。

思路:

既然还有一部分代码要用老的加法器,那么老加法器我们还是要保留的

按照原有思路开发新的加法器CLWeightingAdder

#include <iostream>
using namespace std;
class CLWeightingAdder
{
public:
CLWeightingAdder(int iAugend, int iWeight)
{
m_iAugend = iAugend;
m_iWeight = iWeight;
}
int Add(int iAddend)
{
return m_iAugend * m_iWeight + iAddend;
}
private:
int m_iAugend;
int m_iWeight;
};
int main()
{
CLWeightingAdder adder(2, 3);
cout << adder.Add(5) << endl;
return 0;
}

版本2解决了版本1不能封装数据和方法的问题

版本3:面向对象的思想

需要实现一个加法器:在这个加法器中,已经保存了被加数;现在需要传递加数给这个加法器,以让其返回加法计算结果。
思路:同版本2类似,编写一个加法器的类CLAdder,用一个数据成员保存被加数,然后再写一个虚的public的加法方法

#include <iostream>
using namespace std;
class CLAdder
{
public:
explicit CLAdder(int iAugend)
{
m_iAugend = iAugend;
}
virtual ~CLAdder()
{
}
virtual int Add(int iAddend)
{
return m_iAugend + iAddend;
}
protected:
int m_iAugend;
};
class CLWeightingAdder : public CLAdder
{
public:
CLWeightingAdder(int iAugend, int iWeight) : CLAdder(iAugend)
{
m_iWeight = iWeight;
}
virtual ~CLWeightingAdder()
{
}
virtual int Add(int iAddend)
{
return m_iAugend * m_iWeight + iAddend;
}
protected:
int m_iWeight;
};
int main()
{
CLAdder adder(2);
cout << adder.Add(4) << endl;
CLWeightingAdder wadder(3, 4);
cout << wadder.Add(4) << endl;

return 0;
}

定义成虚函数是十分必要的

如果不定义成虚函数的话,那么静态联编盲目根据指针和引用类型而不是根据实际指向的目标确定调用的函数。

会导致错误。

比如 在上面的额程序中 main函数当中采用 CLAdder *adder = CLWeightingAdder(3,4);

在调用 adder.Add(4)的时候执行的将是基类当中的函数,而这并不是我们想要的。 当然李老师在程序的main部分没有采用这样的写法。

版本3:面向对象的思想

变化来了:现在需要给被加数添加一个权重值;但是以前的加法器仍需保留,因为还有一部分代码会使用它。

思路:

开发新的加法器CLWeightingAdder,让其从CLAdder继承

代码如上

版本3与版本2的比较

版本3和版本2都实现了数据和操纵数据的方法的封装

当引入带权重的加法器时,版本3做到了代码的封闭性,即能封装变化点

void func(CLAdder *pAdder)
{
…………………
pAdder->Add(5);
…………………
}


void f(CLAdder *pAdder)
{
cout << pAdder->Add(4) << endl;
}

当增加带权重加法器时,并不需要修改func的代码 李老师在这一块似乎有问题,上面的程序并没有加入这个函数
这个函数就是证明了的这个问题的。

版本4:基于接口的思想

需要实现一个加法器:在这个加法器中,已经保存了被加数;现在需要传递加数给这个加法器,以让其返回加法计算结果。
普通加法器的被加数,必须是非负的整数,而带权重的加法器的被加数,没有任何限制

思路:定义一个加法接口的抽象类,然后让普通加法器和带权重的加法器从这个抽象类派生

代码1.7

#include <iostream>
using namespace std;
class ILAdder
{
public:
ILAdder()
{
}
virtual ~ILAdder()
{
}
virtual int Add(int iAddend) = 0;
};
class CLAdder : public ILAdder
{
public:
explicit CLAdder(unsigned int iAugend)
{
m_iAugend = iAugend;
}
virtual ~CLAdder()
{
}
virtual int Add(int iAddend)
{
return m_iAugend + iAddend;
}
private:
unsigned int m_iAugend;
};
class CLWeightingAdder : public ILAdder
{
public:
CLWeightingAdder(int iAugend, int iWeight)
{
m_iWeight = iWeight;
m_iAugend = iAugend;
}
virtual ~CLWeightingAdder()
{
}
virtual int Add(int iAddend)
{
return m_iAugend * m_iWeight + iAddend;
}
private:
int m_iAugend;
int m_iWeight;
};
void f(ILAdder *pAdder)
{
cout << pAdder->Add(4) << endl;
}
int main()
{
CLAdder adder(2);
f(&adder);
CLWeightingAdder wadder(3, 4);
f(&wadder);

return 0;
}

上面作者定义了一个抽象类 (包含了纯虚函数)

从而将普通加法器剥离出来,与带权重的加法器成为同一层次的,共同的基类是一个基于接口的抽象类

不过 上面应该将加数 iAddend 设置为unsigned 也就是说题目要求不对,不能体现出版本四的优势。

相关文章

深度解析:清理烂代码
如何编写出拥抱变化的代码
重构-使代码更简洁优美
团队项目开发"编码规范"系列文章
相关文档

重构-改善既有代码的设计
软件重构v2
代码整洁之道
高质量编程规范
相关课程

基于HTML5客户端、Web端的应用开发
HTML 5+CSS 开发
嵌入式C高质量编程
C++高级编程
 
分享到
 
 
   
Visual C++编程命名规则
任何时候都适用的20个C++技巧
C语言进阶
串口驱动分析
轻轻松松从C一路走到C++
C++编程思想
更多...   


C++并发处理+单元测试
C++程序开发
C++高级编程
C/C++开发
C++设计模式
C/C++单元测试


北京 嵌入式C高质量编程
中国航空 嵌入式C高质量编程
华为 C++高级编程
北京 C++高级编程
丹佛斯 C++高级编程
北大方正 C语言单元测试
罗克韦尔 C++单元测试
更多...