程序设计方法(一):结构化、基于对象、面向对象、基于接口

来源:互联网 发布:黑帽seo 流量劫持 编辑:程序博客网 时间:2024/06/05 05:04

公司接到一个项目,实现1个加法器,在项目开发的不同阶段,用户又会提出各种新的要求(即变化点)

版本1:实现一个加法器,加法器中已经保存了被加数,使用加法器的时候,要给他传递一个加数,然后加法器计算并返回相加后的结果;

版本2:(1)被加数在使用时需要乘上权重值,再和加数进行运算;(2)以前的加法器还要保留,因为有部分老用户还会使用老的代码

版本3: 老加法器必须规定被加数是非负的整数,而新加法器被加数可以是正数也可以是负数

一、结构化程序设计

(1)实现版本1

struct SAugend{  int iAugend;};int Add(struct SAugend * pSAugend,int iAddend){  return pSAugend->iAugend + iAddened;}

(2)实现版本2

struct SWeightingAugend{  int iAugend;  int iWeight;};int WeightingAdd(struct SWeightingAugend *pSWeightingAugend, int iAddend){  return pSWeightingAugend->iWeight * pSWeightingAugend->iAugend + iAddend;} 

用户接口,需要在用户的代码中修改函数的调用方式:

void  func(...){  ...  // 修改之前的函数调用  //Add();  WeightingAdd();  ...}
结构化程序设计的缺点分析:

(1)、在实际应用中,通常我们会把struct结构体放到.h文件中,而方法放到其他文件中; 这样本来Add函数就是处理SAugend结构体的(他们俩本是密不可分的),却要被分到两个文件中;这就是所谓的没有封装

(2)、在新版本中,引入变化点后,需要对老代码进行修改;这就失去了代码的封闭性; 所谓代码的封闭性就是说:当项目中扩展了新的功能时,用户代码可以不用修改,就体验到新功能带来的好处(当然,如果用户不想使用新功能,也要允许他使用之前的版本)

二、基于对象的程序设计(不考虑继承,但遵循所有东西都是对象)

(1)版本1

class CAdder{public :  CAdder(int iAugend)  {    m_iAugend = iAugend;   }    int Add(int iAddend)  {    return m_iAugend + iAddend;  }private:  int m_iAugend;};
(2)版本2
class CWeightingAdder{public:  CWeightingAdder(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 func(...){   ...  // 使用新方法时,要修改之前的类定义和方法的调用  // CAdder ca(3);  //int result = ca.Add(2);  CWeightingAdder cwa(3,10);  int result cwa.Add(2);}
分析:

(1)、基于对象的设计,得到的改进是:变量和相关方法实现了封装

(2)、但可以看出,当变化点出现时,用户的接口还是需要修改,即还是没有封装变化点;

三、面向对象的程序设计(面向对象的设计与基于对象的设计的区别是:面向对象多了继承和虚函数)

(1)、版本1

class CAdder{public :  CAdder(int iAugend)  {    m_iAugend = iAugend;  }  virtual ~CAdder()  {  }   virtual int Add(int iAddend)  {   return m_iAugend + iAddend;  }protected:  int m_iAugend;};
(2)版本2
class  CWeightingAdder : public CAdder{public :  CWeightingAdder(int iAugend,int iWeight):CAdder(iAugend)  {    m_iWeight = iWeight;  }  virtual ~CWeightingAdder()  {  }  virtual int Add(int iAddend)  {    return m_iAugend * m_iWeight + iAddend;  }   protected:  int m_iWeight;};

用户接口:

int func(CAdder * pAdder)
{

  ...

  //不需要修改,同一种调用方式(父类指针指向子类对象)

  int result = pAdder->Add(5);

}

分析:

面向对象的程序设计,已经能很好的封装变化点1了,即新功能的引用不影响用户的的程序接口;

关于变化点2:

先在变化点2来了,新问题是,父类的成员变量要改变,而子类的变化点不能改变,而我们使用的是子类直接继承父类成员变量的方法,父类的改变必将牵连子类;所以对于变化点2 ,面向对象的程序设计是不能实现的;

所以从这我们就知道了:继承带来的问题是,父类和子类有强藕合关系,他们失去了独立性


四、基于接口的程序设计(子类和父类之间又继承关系,变成兄弟关系;他们共同继承自他们的抽象或者说他们的共同点---都是加法器)

class IAdder{public:  IAdder()  {  }  virtual  ~IAdder()  {  }  virtual int Add(int iAddend) = 0;}

(1)、版本1

class CAdder : public IAdder{public :  CAdder(unsigned int iAugend)  {  m_iAugend = iAugend;  }  virtual ~CAdder()  {  }  virtual int Add(int iAddend)  {  return m_iAugend+iAddend;  }private:unsigned int m_iAugend;};

(2)版本2

class CWeightingAdder : public IAdder{public :CWeightingAdder (int iAugend,int iWeight){  m_iWeight = iWeight;  m_iAugend = iAugend;}virtual ~CWeightingAdder(){}virtual int Add(int iAddend){  return m_iAugend * m_iWeight + iAddend;}private:int m_iAugend;int m_iWeight;}

用户接口:

int func(IAdder * pAdder){  ...  int result = pAdder->Adder(5);  ...}

用户接口不需要做任何变化,所有的变化点都被封装到实现类中去了。