• 享元模式(flyweight)


    1、作用

    一些对象在使用一次后就可以销毁了,比如画一个圈,这个对象调用draw()函数后,这个对象就没有作用,除非再次画相同的圈。但是在应用中需要画很多圈,如果每次画一次圈都构造一个对象,这样内存消耗很多,构造销毁也很费时,这个时候就可以考虑一下享元模式,这样可以节省内存的开销。

    2、实现方式

    享元模式就很像:工厂模式+单例模式

    (1)、有一个基类,在工厂中作为统一的接口

    (2)、子类是特定功能的类,这类的属性分为两部分:外部属性和内部属性

    内部属性:在构造该类的对象的时候就确定了,通过构造函数的参数来设置,不如圆圈的颜色:color。

    外部属性:在对象构造以后可以修改,通过setXX()成员函数来设置,比如:圈的半径:radius。

    (3)、工厂类:该类有点像单例模式的功能,在特点内部属性的对象已经存在(map中)时,返回存在的对象,不存在时构造一个新对象返回。

    3、C++代码

    Shape.h

    #include <iostream>
    #include <iomanip>
    #include <string>
    
    
    #ifndef __SHAPE__H__
    #define __SHAPE__H__
    
    using namespace std;
    
    
    class Shape {                   // 如果只有Circle这一种图形的话,可有没必要有这个基类,基类作用就是多态性,所有子类都指向基类。
        virtual void draw() = 0;    // 工厂模式必须有一个基类,应该,要产生很多子类对象,工厂的create统一为成基类对象返回。
    };                              // Flyweight模式可以认为是:工厂模式+单例模式
    
    
    class Circle : public Shape {
        public:
    
            // 内部属性通过构造函数设置
            Circle(const string &color):color(color) {
                cout<<"new Circle. color:"<<color<<endl;
            } 
    
            // 外部属性通过set函数设置
            void setX(const int &x) { this->x = x; }
            void setY(const int &y) { this->y = y; }
            void setRadius(const int &r) { this->radius = r; }
    
            // 可以认为是对象重复利用,一个对象------>多个屏幕上的圈(颜色相同),
            // 那种修改原有对象会影响原有效果的不能对象重用。说白了,这里的circle对象是一次性的,对象调用draw()函数后,就完成了使命,可以销毁
            // flyweight模式则不销毁,以便后续有相同需求的时候使用。
            void draw() {
                cout<<"color:"<<setw(8)<<left<<color<<" radius:"<<setw(5)<<radius<<" coordinate:("<<x<<","<<y<<")"<<endl;
            }
        private:
            string color;
            int x;
            int y;
            int radius;
    };
    
    
    
    #endif

    ShapeFactory.h

    #include <iostream>
    #include <string>
    #include <map>
    #include "Shape.h"
    
    #ifndef __SHAPE_FACTORY__H__
    #define __SHAPE_FACTORY__H__
    
    using namespace std;
    
    class ShapeFactory {
        public:
        
            // 工厂函数,在没有构造出相应的对象是构造一个加入到对象池中,否则直接取出对象返回。
            static Shape *getCircle(const string &color) {
                if(shapeMap.find(color) == shapeMap.end()) {     // 第一次查找
                    shapeMap.insert({color, new Circle(color)});
                }
                return shapeMap[color];                          // 第二次查找
            }
            static Shape *getCircle2(const string &color) {
                auto map_it = shapeMap.find(color);              // 只有这一次查找,代码明显复杂了,如果考虑可读性的话,还是选择第一中比较好。
                if(map_it == shapeMap.end()) {
                    auto circle = new Circle(color);
                    shapeMap.insert({color, circle});
                    return circle;
                } else {
                    return map_it->second;      // 这种实现方式少了一次查找过程
                }
            }
        private:
        private:
            // 定义成静态的,所有对象共享这些对象。getCircle也是静态函数,可以不要构造ShapeFactory就能使用。
            static map<string, Shape*> shapeMap;
    };
    
    map<string, Shape*> ShapeFactory::shapeMap = map<string, Shape*>(); // 字面值初始化,构造一个对象初始化:类型()
    
    #endif

    test.cc

    #include "Shape.h"
    #include "ShapeFactory.h"
    
    int main() {
        Circle *circle = static_cast<Circle *>(ShapeFactory::getCircle("black"));
        circle->setX(0);
        circle->setY(0);
        circle->setRadius(10);
        circle->draw();
    
    
        circle = static_cast<Circle *>(ShapeFactory::getCircle("black"));   // black这个内部属性的对象已经存在,使用原有的对象
        circle->setX(20);                                                   // 设置外部属性
        circle->setY(30);
        circle->setRadius(11);
        circle->draw();
    
        circle = static_cast<Circle *>(ShapeFactory::getCircle("red"));     // red这个内部属性的对象不存在,新构造一个
        circle->setX(20);                                                   // 设置外部属性
        circle->setY(30);
        circle->setRadius(11);
        circle->draw();
    
        return 0;
    }

    输出:

  • 相关阅读:
    【转】linux常用命令
    【转】C++三大特性
    插入排序
    shixi
    【转】TCP协议
    【转】排序算法稳定性
    面筋BD
    斐波那契数列
    【面试题】D
    【学习笔记】OI模板整理
  • 原文地址:https://www.cnblogs.com/yuandonghua/p/11883513.html
Copyright © 2020-2023  润新知