23种设计模式-享元(Flyweight)设计模式
文章目录
- 一.什么是享元设计模式?
- 二.享元模式的特点
- 三.享元模式的结构
- 四.享元模式的优缺点
- 五.享元模式的 C++ 实现
- 六.享元模式的 JAVA 实现
- 七.代码解析
- 八.总结
类图: 享元设计模式类图
一.什么是享元设计模式?
享元(Flyweight)设计模式是一种结构型设计模式,通过共享对象来减少内存占用和对象创建开销。它通过将对象的可共享部分与不可共享部分分离,减少重复对象的数量,从而节省内存。
享元模式的核心思想是共享对象状态,在需要大量相似对象时,仅存储少量可复用的对象,其他状态通过外部管理。
二.享元模式的特点
- 共享性:通过共享相同状态的对象,降低内存占用。
- 分离状态:
- 内部状态:对象内部不变的部分,可共享。
- 外部状态:对象动态变化的部分,由客户端负责管理。
三.享元模式的结构
- Flyweight(抽象享元类):定义对象共享的接口,通常是一个轻量化接口。
- ConcreteFlyweight(具体享元类):实现抽象享元类,存储对象的共享部分。
- UnsharedConcreteFlyweight(非共享享元类):不需要共享的对象。
- FlyweightFactory(享元工厂类):管理享元对象的创建和共享。
- Client(客户端):负责维护外部状态,调用享元对象完成操作。
四.享元模式的优缺点
- 优点:
- 减少对象创建,节省内存。
- 提高性能,尤其是在需要大量相似对象时。
- 缺点:
- 增加了系统复杂性:需要分离内部状态和外部状态。
- 需要确保外部状态的正确性,否则可能导致数据问题。
五.享元模式的 C++ 实现
以下代码实现了一个场景:在一片森林中种植多棵树,树的种类是共享的(享元对象),而每棵树的位置是外部状态。
#include <iostream>
#include <unordered_map>
#include <string>
#include <memory>
using namespace std;
// 抽象享元类
class TreeType {
protected:
string name; // 树的名称
string color; // 树的颜色
string texture; // 树的纹理
public:
TreeType(const string& name, const string& color, const string& texture)
: name(name), color(color), texture(texture) {}
virtual void Display(int x, int y) const = 0; // 显示树的信息
virtual ~TreeType() = default;
};
// 具体享元类
class ConcreteTreeType : public TreeType {
public:
ConcreteTreeType(const string& name, const string& color, const string& texture)
: TreeType(name, color, texture) {}
void Display(int x, int y) const override {
cout << "Tree [Type: " << name
<< ", Color: " << color
<< ", Texture: " << texture
<< "] at (" << x << ", " << y << ")" << endl;
}
};
// 享元工厂类
class TreeFactory {
private:
unordered_map<string, shared_ptr<TreeType>> treeTypes; // 存储享元对象
public:
shared_ptr<TreeType> GetTreeType(const string& name, const string& color, const string& texture) {
string key = name + "_" + color + "_" + texture;
if (treeTypes.find(key) == treeTypes.end()) {
// 如果对象不存在,则创建新的享元对象
treeTypes[key] = make_shared<ConcreteTreeType>(name, color, texture);
cout << "Created new TreeType: " << key << endl;
}
return treeTypes[key];
}
};
// 客户端类:表示单棵树
class Tree {
private:
shared_ptr<TreeType> type; // 树的种类(享元对象)
int x, y; // 树的位置(外部状态)
public:
Tree(int x, int y, shared_ptr<TreeType> type) : x(x), y(y), type(type) {}
void Display() const {
type->Display(x, y); // 调用享元对象的 Display 方法
}
};
// 主函数
int main() {
TreeFactory factory;
// 创建森林中的树
shared_ptr<Tree> tree1 = make_shared<Tree>(10, 20, factory.GetTreeType("Oak", "Green", "Smooth"));
shared_ptr<Tree> tree2 = make_shared<Tree>(15, 25, factory.GetTreeType("Pine", "Dark Green", "Rough"));
shared_ptr<Tree> tree3 = make_shared<Tree>(10, 20, factory.GetTreeType("Oak", "Green", "Smooth")); // 复用已有类型
// 显示所有树
tree1->Display();
tree2->Display();
tree3->Display();
return 0;
}
六.享元模式的 JAVA 实现
import java.util.HashMap;
import java.util.Map;
// 抽象享元类
abstract class TreeType {
protected String name;
protected String color;
protected String texture;
public TreeType(String name, String color, String texture) {
this.name = name;
this.color = color;
this.texture = texture;
}
public abstract void display(int x, int y);
}
// 具体享元类
class ConcreteTreeType extends TreeType {
public ConcreteTreeType(String name, String color, String texture) {
super(name, color, texture);
}
@Override
public void display(int x, int y) {
System.out.println("Tree [Type: " + name + ", Color: " + color + ", Texture: " + texture
+ "] at (" + x + ", " + y + ")");
}
}
// 享元工厂类
class TreeFactory {
private Map<String, TreeType> treeTypes = new HashMap<>();
public TreeType getTreeType(String name, String color, String texture) {
String key = name + "_" + color + "_" + texture;
if (!treeTypes.containsKey(key)) {
treeTypes.put(key, new ConcreteTreeType(name, color, texture));
System.out.println("Created new TreeType: " + key);
}
return treeTypes.get(key);
}
}
// 客户端类:单棵树
class Tree {
private TreeType type; // 树的类型(享元对象)
private int x, y; // 树的位置(外部状态)
public Tree(int x, int y, TreeType type) {
this.x = x;
this.y = y;
this.type = type;
}
public void display() {
type.display(x, y); // 调用享元对象的 display 方法
}
}
// 主函数
public class FlyweightPatternDemo {
public static void main(String[] args) {
TreeFactory factory = new TreeFactory();
// 创建森林中的树
Tree tree1 = new Tree(10, 20, factory.getTreeType("Oak", "Green", "Smooth"));
Tree tree2 = new Tree(15, 25, factory.getTreeType("Pine", "Dark Green", "Rough"));
Tree tree3 = new Tree(10, 20, factory.getTreeType("Oak", "Green", "Smooth")); // 复用已有类型
// 显示所有树
tree1.display();
tree2.display();
tree3.display();
}
}
七.代码解析
- TreeType 和 ConcreteTreeType(享元类):
- TreeType 是抽象基类,定义了树的名称、颜色、纹理等共享部分。
- ConcreteTreeType 是具体实现,包含共享的树种信息。
- TreeFactory(享元工厂类):
- 工厂类维护一个哈希表(unordered_map),用于存储和复用享元对象。
- 当请求一个 TreeType 时,如果已有共享对象,直接返回;否则创建新对象。
- Tree(客户端类):
- Tree 对象包含外部状态(位置坐标 x 和 y),同时持有一个指向 TreeType 的指针。
- 外部状态由客户端管理,享元对象不直接维护。
- 运行结果:
- 创建新的 TreeType 时,工厂输出 “Created new TreeType”。
- 共享的 TreeType 只会创建一次,相同类型的树直接复用。
八.总结
享元模式通过共享相同类型的对象,减少内存开销,非常适合需要大量重复对象的场景。然而,使用享元模式需要注意内部状态与外部状态的划分,同时管理外部状态的复杂性可能增加。
应用场景:
- 游戏开发:重复的图形元素(如树木、建筑物)可以共享对象。
- 文本编辑器:字符对象的字体、颜色等共享,而具体位置动态维护。
- 网络连接池:数据库或网络连接共享对象,节约资源。