享元模式--结构型模式

1、描述

享元是一种结构型设计模式,它允许你在消耗少量内存的情况下支持大量对象。

模式通过共享多个对象的部分状态来实现上述功能。换句话说,享元会将不同对象的相同数据进行缓存以节省内存。

内部状态:内部状态是对象可共享出来的信息,存储在享元对象内部并且不会随环境改变而改变。

外部状态:外部状态是对象得以依赖的一个标记,是随环境改变而改变的、不可共享的状态。

优点:享元模式是一个非常简单的模式,它可以大大减少应用程序创建的对象,降低程序内存的占用,增强程序的性能,但它同时也提高了系统的复杂性,需要分离外部状态和内部状态,而且内部状态具有固化特性,不应该随外部状态改变而改变,否则导致系统的逻辑混乱。

2、结构图

  • 享元模式只是一种优化。在应用该模式之前,你要确定程序中存在与大量类似对象同时占用内存相关的内存消耗问题,并且确保该问题无法使用其他更好的方式来解决。
  • 享元(Flyweight)类包含原始对象中部分能在多个对象中共享的状态。同一享元对象可在许多不同情景中使用。享元中存储的状态被称为“内在状态”。传递给享元方法的状态被称为“外在状态”
  • 情景(Context)类包含原始对象中各不相同的外在状态。情景与享元对象组合在一起就能表示原始对象的全部状态
  • 通常情况下,原始对象的行为会保留在享元类中。因此调用享元方法必须提供部分外在状态作为参数。但你也可将行为移动到情景类中,然后将连入的享元作为单纯的数据对象。
  • Client负责计算或存储享元的外在状态。在Client看来,享元是一种可在运行时进行配置的模板对象,具体的配置方式为向其方法中传入一些情景数据参数。
  • 享元工厂(Flyweight Factory)会对已有享元的缓存池进行管理。有了工厂后,客户端就无需直接创建享元,它们只需调用工厂并向其传递目标享元的一些内在状态即可。工厂会根据参数在之前已创建的享元中查找,如果找到满足条件的享元就将其返回;如果没有找到就根据参数新建享元。

3、C++代码

#include <string>
#include <iostream>
#include <unordered_map>

//通过共享多个对象所共有的相同状态, 让你能在有限的内存容量中载入更多对象。
struct SharedState
{
    std::string brand_;
    std::string model_;
    std::string color_;

    SharedState(const std::string &brand, const std::string &model, const std::string &color)
        : brand_(brand), model_(model), color_(color)
    {
    }

    friend std::ostream &operator<<(std::ostream &os, const SharedState &ss)
    {
        return os << "[ " << ss.brand_ << " , " << ss.model_ << " , " << ss.color_ << " ]";
    }
};

struct UniqueState
{
    std::string owner_;
    std::string plates_;

    UniqueState(const std::string &owner, const std::string &plates)
        : owner_(owner), plates_(plates)
    {
    }

    friend std::ostream &operator<<(std::ostream &os, const UniqueState &us)
    {
        return os << "[ " << us.owner_ << " , " << us.plates_ << " ]";
    }
};

//享元存储属于多个实际业务实体的公共部分(也称为内在状态)。
//享元通过其方法参数接受状态的其余部分(分部状态,每个实体都是唯一的)。
class Flyweight
{
private:
    SharedState *shared_state_;

public:
    Flyweight(const SharedState *shared_state) : shared_state_(new SharedState(*shared_state))
    {
    }
    Flyweight(const Flyweight &other) : shared_state_(new SharedState(*other.shared_state_))
    {
    }
    ~Flyweight()
    {
        delete shared_state_;
    }
    SharedState *shared_state() const
    {
        return shared_state_;
    }
    void Operation(const UniqueState &unique_state) const
    {
        std::cout << "Flyweight: Displaying shared (" << *shared_state_ << ") and unique (" << unique_state << ") state.\n";
    }
};

//享元工厂创建和管理享元对象。确保享元对象被正确的共享。当客户请求一个享元的时候,
//工厂要么返回一个已经存在的实例,要么创建一个新的。
class FlyweightFactory
{
private:
    std::unordered_map<std::string, Flyweight> flyweights_;

    std::string GetKey(const SharedState &ss) const
    {
        return ss.brand_ + "_" + ss.model_ + "_" + ss.color_;
    }

public:
    FlyweightFactory(std::initializer_list<SharedState> share_states)
    {
        for (const SharedState &ss : share_states)
        {
            this->flyweights_.insert(std::make_pair<std::string, Flyweight>(this->GetKey(ss), Flyweight(&ss)));
        }
    }

    //返回一个已经存在的实例,如果不存在,那么创建一个新的。
    Flyweight GetFlyweight(const SharedState &shared_state)
    {
        std::string key = this->GetKey(shared_state);
        if (this->flyweights_.find(key) == this->flyweights_.end())
        {
            std::cout << "FlyweightFactory: Can't find a flyweight, creating new one.\n";
            this->flyweights_.insert(std::make_pair(key, Flyweight(&shared_state)));
        }
        else
        {
            std::cout << "FlyweightFactory: Reusing existing flyweight.\n";
        }
        return this->flyweights_.at(key);
    }
    void ListFlyweights() const
    {
        size_t count = this->flyweights_.size();
        std::cout << "\nFlyweightFactory: I have " << count << " flyweights:\n";
        for (std::pair<std::string, Flyweight> pair : this->flyweights_)
        {
            std::cout << pair.first << "\n";
        }
    }
};

// ...
void AddCarToPoliceDatabase(
    FlyweightFactory &ff, const std::string &plates, const std::string &owner,
    const std::string &brand, const std::string &model, const std::string &color)
{
    std::cout << "\nClient: Adding a car to database.\n";
    const Flyweight &flyweight = ff.GetFlyweight({brand, model, color});
    //客户代码存储或计算外部状态并将其传递给flyweight的方法。
    flyweight.Operation({plates, owner});
}

//客户代码通常在应用程序的初始化阶段创建一组预填充的flyweight。
int main()
{
    FlyweightFactory *factory = new FlyweightFactory({{"Chevrolet", "Camaro2018", "pink"}, {"Mercedes Benz", "C300", "black"}, {"Mercedes Benz", "C500", "red"}, {"BMW", "M5", "red"}, {"BMW", "X6", "white"}});
    factory->ListFlyweights();

    AddCarToPoliceDatabase(*factory,
                            "CL234IR",
                            "James Doe",
                            "BMW",
                            "M5",
                            "red");

    AddCarToPoliceDatabase(*factory,
                            "CL234IR",
                            "James Doe",
                            "BMW",
                            "X1",
                            "red");
    factory->ListFlyweights();
    delete factory;

    return 0;
}

参考

https://refactoringguru.cn/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值