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

公司接到一个项目,实现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);

  ...

}

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

你可能感兴趣的:(程序设计方法(一):结构化、基于对象、面向对象、基于接口)