《设计模式的艺术》笔记 - 享元模式

介绍

享元模式运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。由于享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻量级模式,是一种对象结构型模式。

实现

myclass.h

cpp 复制代码
//
// Created by yuwp on 2024/1/12.
//

#ifndef DESIGNPATTERNS_MYCLASS_H
#define DESIGNPATTERNS_MYCLASS_H

#include <iostream>
#include <unordered_map>

class Flyweight {   // 享元抽象类
public:
    Flyweight(const std::string &in);
    virtual void operation(const std::string &out) = 0;

    const std::string &getMIn() const;

private:
    std::string m_in;
};

class ConcreteFlyweight : public Flyweight {    // 具体享元类
public:
    ConcreteFlyweight(const std::string &in);

    void operation(const std::string &out) override;
};

class FlyweightFactory {    // 配合工厂模式使用享元工厂类
public:
    ~FlyweightFactory();
    Flyweight *getFlyweight(const std::string &key);
private:
    std::unordered_map<std::string, Flyweight *> m_flyweights;
};

#endif //DESIGNPATTERNS_MYCLASS_H

myclass.cpp

cpp 复制代码
//
// Created by yuwp on 2024/1/12.
//

#include "myclass.h"

Flyweight::Flyweight(const std::string &in) {
    m_in = in;
}

const std::string &Flyweight::getMIn() const {
    return m_in;
}

ConcreteFlyweight::ConcreteFlyweight(const std::string &in) : Flyweight(in) {

}

void ConcreteFlyweight::operation(const std::string &out) {
    std::cout<< "内部状态: " << getMIn() << ", 外部状态: " << out << std::endl;
}

FlyweightFactory::~FlyweightFactory() {
    for (auto it : m_flyweights) {
        if (it.second) {
            delete it.second;
        }
    }
}

Flyweight* FlyweightFactory::getFlyweight(const std::string &key) {
    auto it = m_flyweights.find(key);
    if (it != m_flyweights.end()) {
        return it->second;
    } else {
        Flyweight *flyweight = new ConcreteFlyweight(key);
        m_flyweights.insert(std::make_pair(key, flyweight));
        return flyweight;
    }
}

main.cpp

cpp 复制代码
#include <iostream>
#include <mutex>
#include "myclass.h"

int main() {
    FlyweightFactory *factory = new FlyweightFactory();
    auto fly1 = factory->getFlyweight("a");
    auto fly2 = factory->getFlyweight("b");
    auto fly3 = factory->getFlyweight("a");
    fly1->operation("1");
    fly2->operation("2");
    fly3->operation("3");

    delete factory;

    return 0;
}

总结

优点

  1. 可以极大减少内存中对象的数量,使得相同或相似对象在内存中只保存一份,从而可以节约系统资源,提高系统性能。

  2. 享元模式的外部状态相对独立,而且不会影响其内部状态,从而使得享元对象可以在不同的环境中被共享。

缺点

  1. 享元模式需要分离出内部状态和外部状态,从而使得系统变得复杂,这使得程序的逻辑复杂化。

  2. 为了使对象可以共享,享元模式需要将享元对象的部分状态外部化,而读取外部状态将使得运行时间变长。

适用场景

  1. 一个系统有大量相同或者相似的对象,造成内存的大量耗费。

  2. 对象的大部分状态都可以外部化,可以将这些外部状态传入对象中。

  3. 在使用享元模式时需要维护一个存储享元对象的享元池,而这需要耗费一定的系统资源。因此,在需要多次重复使用同一享元对象时才值得使用享元模式。

练习

myclass.h

cpp 复制代码
//
// Created by yuwp on 2024/1/12.
//

#ifndef DESIGNPATTERNS_MYCLASS_H
#define DESIGNPATTERNS_MYCLASS_H

#include <iostream>
#include <unordered_map>

class Flyweight {   // 享元抽象类
public:
    Flyweight(const std::string &in);
    virtual void display(const std::string &out) = 0;

    const std::string &getMIn() const;

private:
    std::string m_in;
};

class PictureFlyweight : public Flyweight {    // 具体享元类
public:
    PictureFlyweight(const std::string &in);

    void display(const std::string &out) override;
};

class AnimationFlyweight : public Flyweight {    // 具体享元类
public:
    AnimationFlyweight(const std::string &in);

    void display(const std::string &out) override;
};

class VideoFlyweight : public Flyweight {    // 具体享元类
public:
    VideoFlyweight(const std::string &in);

    void display(const std::string &out) override;
};

class FlyweightFactory {    // 配合工厂模式使用享元工厂类
public:
    ~FlyweightFactory();
    Flyweight *getFlyweight(const std::string &key);
    static FlyweightFactory *getInstance();
private:
    FlyweightFactory();

    std::unordered_map<std::string, Flyweight *> m_flyweights;
};

#endif //DESIGNPATTERNS_MYCLASS_H

myclass.cpp

cpp 复制代码
//
// Created by yuwp on 2024/1/12.
//

#include "myclass.h"

Flyweight::Flyweight(const std::string &in) {
    m_in = in;
}

const std::string &Flyweight::getMIn() const {
    return m_in;
}

PictureFlyweight::PictureFlyweight(const std::string &in) : Flyweight(in) {

}

void PictureFlyweight::display(const std::string &out) {
    std::cout << out << ", " << getMIn() << std::endl;
}

AnimationFlyweight::AnimationFlyweight(const std::string &in) : Flyweight(in) {

}

void AnimationFlyweight::display(const std::string &out) {
    std::cout << out << ", " << getMIn() << std::endl;
}

VideoFlyweight::VideoFlyweight(const std::string &in) : Flyweight(in) {

}

void VideoFlyweight::display(const std::string &out) {
    std::cout << out << ", " << getMIn() << std::endl;
}

FlyweightFactory::FlyweightFactory() {

}

FlyweightFactory* FlyweightFactory::getInstance() {
    static FlyweightFactory *factory = new FlyweightFactory();
    return factory;
}

FlyweightFactory::~FlyweightFactory() {
    for (auto it : m_flyweights) {
        if (it.second) {
            delete it.second;
        }
    }
}

Flyweight* FlyweightFactory::getFlyweight(const std::string &key) {
    auto it = m_flyweights.find(key);
    if (it != m_flyweights.end()) {
        return it->second;
    } else {
        Flyweight *flyweight = nullptr;
        if (key == "图片") {
            flyweight = new PictureFlyweight(key);
        } else if (key == "动画") {
            flyweight = new AnimationFlyweight(key);
        } else if (key == "视频") {
            flyweight = new VideoFlyweight(key);
        }
        m_flyweights.insert(std::make_pair(key, flyweight));
        return flyweight;
    }
}

main.cpp

cpp 复制代码
#include <iostream>
#include <mutex>
#include "myclass.h"

int main() {
    FlyweightFactory *factory = FlyweightFactory::getInstance();
    factory->getFlyweight("图片")->display("1");
    factory->getFlyweight("动画")->display("2");
    factory->getFlyweight("视频")->display("3");
    factory->getFlyweight("图片")->display("4");

    return 0;
}
相关推荐
雨中飘荡的记忆38 分钟前
深入理解设计模式之单例模式
java·设计模式
8***29312 小时前
能懂!基于Springboot的用户增删查改(三层设计模式)
spring boot·后端·设计模式
love530love3 小时前
【保姆级教程】Windows + Podman 从零部署 Duix-Avatar 数字人项目
人工智能·windows·笔记·python·数字人·podman·duix-avatar
草莓熊Lotso4 小时前
《算法闯关指南:动态规划算法--斐波拉契数列模型》--01.第N个泰波拉契数,02.三步问题
开发语言·c++·经验分享·笔记·其他·算法·动态规划
FFF团团员90911 小时前
树莓派学习笔记3:LED和Button
笔记·学习
在未来等你11 小时前
AI Agent设计模式 Day 19:Feedback-Loop模式:反馈循环与自我优化
设计模式·llm·react·ai agent·plan-and-execute
碧海潮生_CC12 小时前
【CUDA笔记】04 CUDA 归约, 原子操作,Warp 交换
笔记·cuda
摇滚侠12 小时前
2025最新 SpringCloud 教程,从单体到集群架构,笔记02
笔记·spring cloud·架构
风123456789~13 小时前
【OceanBase专栏】OB背景知识
数据库·笔记·oceanbase
智者知已应修善业14 小时前
【51单片机普通延时奇偶灯切换】2023-4-4
c语言·经验分享·笔记·嵌入式硬件·51单片机