【设计模式】04原型模式学习笔记(cloneable)

菜鸟教程连接https://www.runoob.com/design-pattern/prototype-pattern.html

《大话设计模式》的UML类图入下 :

【设计模式】04原型模式学习笔记(cloneable)

菜鸟教程的UML类图如下:

【设计模式】04原型模式学习笔记(cloneable)

解决的问题 :

  • 在运行期间建立和删除原型
  • 逃避构造函数的约束
  1. 接口类ICloneable.hpp里要有clone()函数

    #ifndef _ICLONEABLE_H 
    #define _ICLONEABLE_H 
    
    #include <stdlib.h> 
    #include "MajiaoObject.hpp" 
     
    class ICloneable : public MajiaoObject { 
        public :  
            ICloneable() {  } 
            ~ICloneable() {  } 
            
            // 纯虚函数
            virtual ICloneable* clone() = 0;
    		
        	// 一个简单拷贝,浅拷贝
            virtual ICloneable* clone(int objSize) {
                char* objClone = (char*) malloc(objSize);
                memcpy(objClone, this, objSize);
                return (ICloneable*) objClone;
            }
    }; 
    #endif	// _ICLONEABLE_H
    
  2. 图形类Shape要实现ICloneable的函数

    #ifndef _SHAPE_H 
    #define _SHAPE_H 
    #include "ICloneable.hpp" 
     
    class Shape : public ICloneable { 
        public :  
            int color;
            int w, h;
            Shape() {  } 
            ~Shape() {  } 
    		
        	// 重写父类的clone函数
            virtual ICloneable* clone() override {
                Shape* objClone = new Shape();
                *objClone = *this;
                return objClone;
            }
    
            virtual double calcArea() {
                return w * h;
            }
    }; 
    #endif	// _SHAPE_H
    
  3. 图形的子类CircleRectOval都要重写父类的clone()

    • 没有新的成员变量,可以用父类的clone()

      #ifndef _RECT_H 
      #define _RECT_H 
       
      #include "Shape.hpp" 
      
      // Rect没有重写clone,因为没有新的成员变量,可以直接用父类的clone
      class Rect : public Shape { 
          public :  
              Rect() {  } 
              ~Rect() {  } 
      }; 
      #endif	// _RECT_H
      
    • 有新的成员变量,需要重写clone()

      #ifndef _OVAL_H 
      #define _OVAL_H 
      
      #include <math.h> 
      #include "Shape.hpp" 
       
      // 椭圆
      class Oval : public Shape { 
          public :  
      
              double a, b, c;
      
              // 焦点,在x轴上,在y轴上
              enum FOCUS { FOCUS_X, FOCUS_Y };
      
              Oval() {  } 
              ~Oval() {  } 
      		
          	// 有新成员a,b,c,要重写拷贝
              virtual ICloneable* clone() override {
                  // Oval* objClone = new Oval();
                  // *objClone = *this;
                  // return (ICloneable*)(objClone);
                  return ICloneable::clone(sizeof(Oval));
              }
      
              virtual double calcArea() {
                  // S = PI * A * B
                  return acos(-1) * a * b;
              }
      }; 
      #endif	// _CIRCLE_H
      
    • 当有成员变量是指针时,要深拷贝,书上重载了构造函数,在构造的时候clone

      #ifndef _CIRCLE_H 
      #define _CIRCLE_H 
      
      #include "Oval.hpp" 
      
      // 圆形是特殊的椭圆,使用装饰器(这里其实应该继承,用装饰器只是为了演示“有指针变量”的clone)
      class Circle : public Oval { 
          public :  
              Oval* oval;
              Circle() { }
      
              // 书上说,在构造里添加一个对 成员指针的clone即可
              Circle(Oval* oval) { 
                  this->oval = (Oval*) oval->clone();
              } 
              ~Circle() {  } 
      
              virtual ICloneable* clone() {
                  // 调用构造去克隆成员指针
                  Circle* objClone = new Circle(this->oval);
                  objClone->h = this->h;
                  objClone->w = this->w;
                  objClone->color = this->color;
                  return objClone;
              }
      }; 
      #endif	// _CIRCLE_H
      
  4. 在调用方就直接xxx->clone()即可

    signed main() {
        Shape* shape = new Rect(),
               *oval = new Oval();
        Circle *circle = new Circle(new Oval()); 
        circle->oval->a = 999;
        shape->color = 0xff;
        circle->color = 0x77;
        // 两种clone方式
        ICloneable *rectColone = shape->clone(), 
        			//成员变量浅拷贝,成员变量是指针类型时要小心
                   *rectClone2 = shape->
                       ICloneable::clone(int(sizeof(Shape))), 
                   *overClone = oval->clone(),
                   // "成员变量是指针" 的深拷贝clone方式
                   *circleClone = circle->clone();
    
        cout << shape->color << endl;
        cout << ((Shape*)rectColone)->color << endl;
        cout << ((Shape*)rectClone2)->color << endl;
        cout << ((Shape*)circleClone)->color << "  " << ((Circle*)circleClone)->oval->a << endl;
        return 0;
    }
    
    
  5. TODO,使用宏来实现clone()函数

上一篇:Object类方法


下一篇:【大话设计模式】原型模式