理解C++基本设计模式

一、开放封闭原则示例:

一个图形绘制函数,要求能够针对输入的不同对象,调用不同的绘制函数,如能够绘制矩形,圆形,调用相应的绘制函数。

1.  c语言实现,这个例子其实给出了c语言模拟c++类继承的方法。利用指针的强制转换,因为指针仅仅是地址可以指向任何对象,利

用指针强制转换,告诉编译器具体按什么对象处理指针所指。

Listing 1

enum ShapeType {circle, square};

struct Shape

{

    ShapeType itsType;

};

struct Circle

{

    ShapeType itsType;

    double itsRadius;

    Point itsCenter;

};

struct Square

{

    ShapeType itsType;

    double itsSide;

    Point itsTopLeft;

};

// 下面两个函数的实现定义在别处

void DrawSquare(struct Square*)

void DrawCircle(struct Circle*);

typedef struct Shape *ShapePointer;

void DrawAllShapes(ShapePointer list[], int n)

{       

int i;

    for (i=0; i<n; i++)

   {

        struct Shape* s = list[i];

        switch (s->itsType)

        {

          case square:

              DrawSquare((struct Square*)s);

              break;

         case circle:

             DrawCircle((struct Circle*)s);

             break;

        }

     }

}

这段代码用C模拟的C++的对象设计。

上面的代码不符合open close法则,因为新加入其它的shape如椭圆, DrawAllShapes函数就需要变化。

2. C++的实现

Listing 2

/*OOD solution to Square/Circle problem.*/

class Shape

{

    public:

        virtual void Draw() const = 0;

};

class Square : public Shape

{

    public:

        virtual void Draw() const;

};

class Circle : public Shape

{

    public:

        virtual void Draw() const;

};

void DrawAllShapes(Set<Shape*>& list)

{

    for (Iterator<Shape*>i(list); i; i++)

        (*i)->Draw();

}

和上面C语言实现代码对比,显然符合open close 法则,加入新的shape DrawAllShapes函数可保持不变,只是添加新的shape内容。

二、里氏代换原则示例:

为了说明,我们先用第一种方法来看一个例子,第二种办法在另外一个原则中说明.

我们就看那个著名的长方形和正方形的例子。对于长方形的类,如果它的长宽相等,那么它就是一个正方形,因此,长方形类的对象中有一些正方形的对象。对于一个正方形的类,它的方法有setSidegetSide,它不是长方形的子类,和长方形也不会符合LSP

  eg:

  长方形类:

  public class Rectangle{

  ...

  setWidth(int width){

  this.width=width;

  }

  setHeight(int height){

  this.height=height

  }

  }

  正方形类:

  public class Square{

  ...

  setWidth(int width){

  this.width=width;

  this. height=width;

  }

  setHeight(int height){

  this.setWidth(height);

  }

  }

  例子中改变边长的函数:

  public void resize(Rectangle r){

  while(r.getHeight()<r.getWidth){

  r.setHeight(r.getWidth+1);

  }

  }

  那么,如果让正方形当做是长方形的子类,会出现什么情况呢?我们让正方形从长方形继承,然后在它的内部设置width等于height,这样,只要width或者height被赋值,那么widthheight会被同时赋值,这样就保证了正方形类中widthheight总是相等的.现在我们假设有个客户类,其中有个方法,规则是这样的,测试传入的长方形的宽度是否大于高度,如果满足就停止下来,否则就增加宽度的值。现在我们来看,如果传入的是基类长方形,这个运行的很好。根据LSP,我们把基类替换成它的子类,结果应该也是一样的,但是因为正方形类的widthheight会同时赋值,这个方法没有结束的时候,条件总是不满足,也就是说,替换成子类后,程序的行为发生了变化,它不满足LSP

  那么我们用第一种方案进行重构,我们构造一个抽象的四边形类,把长方形和正方形共同的行为放到这个四边形类里面,让长方形和正方形都是它的子类,问题就OK了。对于长方形和正方形,取widthheight是它们共同的行为,但是给widthheight赋值,两者行为不同,因此,这个抽象的四边形的类只有取值方法,没有赋值方法。上面的例子中那个方法只会适用于不同的子类,LSP也就不会被破坏。

在进行设计的时候,我们尽量从抽象类继承,而不是从具体类继承。如果从继承等级树来看,所有叶子节点应当是具体类,而所有的树枝节点应当是抽象类或者接口。当然这个只是一个一般性的指导原则。使用的时候还要具体情况具体分析.

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值