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

介绍

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

实现

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;
}
相关推荐
严文文-Chris3 分钟前
【设计模式-命令】
设计模式·命令模式
零星_AagT9 分钟前
红日靶机(二)笔记
windows·笔记·域渗透·vulnstack
@qike14 分钟前
【C++】——类和对象(上)
java·开发语言·jvm·数据结构·c++·笔记·算法
楠了个难1 小时前
SPI通信——FPGA学习笔记14
笔记·学习·fpga开发
Daniel_10111 小时前
高斯消元 笔记
笔记
zhangrelay1 小时前
谈及医疗和教育真实需求是什么
笔记·学习·持续学习
结衣结衣.1 小时前
程序地址空间
linux·c语言·笔记·学习·操作系统
逻辑与&&2 小时前
[Docker学习笔记]Docker的原理&&Docker常见命令
linux·运维·笔记·学习·docker
刷帅耍帅2 小时前
设计模式-抽象工厂模式
设计模式·抽象工厂模式
夜流冰2 小时前
工程师 - 如何配置DNS服务器
笔记