享元模式是用来节省内存空间,提升效率的模式。只有当对象相当之多时,才需要使用。
#include <iostream>
#include <string>
#include <list>
using namespace std;
template <typename T>
class Singleton {
public:
//外部获取单例的接口
static T& getInstance() {
static Token token;
static T instance(token); //函数静态变量可以实现延时构造。
return instance;
}
//禁止拷贝
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
protected:
//只有子类才能获取令牌。
struct Token{};
//构造和析构函数私有化
Singleton() = default;
virtual ~Singleton() = default;
};
struct Pos {
int x;
int y;
Pos(int x, int y) : x(x), y(y) {}
friend ostream &operator<<(ostream &os, const Pos &pos) {
os << "x: " << pos.x << " y: " << pos.y;
return os;
}
};
//非享元模式
namespace unFlyweight {
class Plant {
public:
Plant(int x, int y) : pos(x, y) {}
virtual void draw() = 0;
virtual ~Plant() = default;
protected:
Pos pos;
};
class Grass : public Plant {
public:
Grass(int x, int y) : Plant(x, y) {}
void draw() {
cout << "在" << pos << "处有一颗草" << endl;
}
};
class Tree : public Plant {
public:
Tree(int x, int y) : Plant(x, y) {}
void draw() {
cout << "在" << pos << "处有一颗树" << endl;
}
};
}
//享元模式
namespace Flyweight {
class Plant {
public:
virtual void draw(const Pos &pos) = 0;
virtual ~Plant() = default;
};
//可以是单例
class Grass : public Plant, public Singleton<Grass> {
public:
explicit Grass(Token token) {}
void draw(const Pos &pos) override {
cout << "在" << pos << "处有一颗草" << endl;
}
};
//可以是单例
class Tree : public Plant, public Singleton<Tree> {
public:
explicit Tree(Token token) {}
void draw(const Pos &pos) override {
cout << "在" << pos << "处有一颗树" << endl;
}
};
}
int main()
{
//不用享元模式
list<unFlyweight::Tree> trees;
for (int i = 0; i < 1000000; ++i) {
trees.emplace_back(i, -i);
}
for (auto &tree : trees) {
tree.draw();
}
//用享元模式
list<Pos> treesPos;
for (int i = 0; i < 1000000; ++i) {
treesPos.emplace_back(i, -i);
}
for (auto &pos : treesPos) {
Flyweight::Tree::getInstance().draw(pos);
}
return 0;
}
也可以用享元池的方式。本文通过单例的getInstance
通过泛型编程实现(编译时)多态。
享元模式有内部状态和外部状态,draw
就是内部状态,pos
就是外部状态。所有的对象一起共享内部状态,但是需要数据结构维护来外部补状态。数量不是特别大的时候不需要使用这个模式。