23种设计模式‑享元(Flyweight)设计模式

📅 发布时间:2026/10/1 7:46:17
23种设计模式‑享元(Flyweight)设计模式
文章目录一.什么是享元设计模式二.享元模式的特点三.享元模式的结构四.享元模式的优缺点五.享元模式的 C 实现六.享元模式的 JAVA 实现七.代码解析八.总结类图享元设计模式类图一.什么是享元设计模式享元Flyweight设计模式是一种结构型设计模式通过共享对象来减少内存占用和对象创建开销。它通过将对象的可共享部分内部状态与不可共享部分外部状态分离减少重复对象的数量从而节省内存。享元模式的核心思想是共享对象状态在需要大量相似对象时仅存储少量可复用的对象其他状态通过外部管理。二.享元模式的特点共享性通过共享相同状态的对象降低内存占用。分离状态内部状态对象内部不变的部分可以被多个对象共享存放在享元对象内部。外部状态对象动态变化的部分不能共享由客户端负责维护、传入。核心区分内部状态不随场景改变外部状态随使用场景变化不保存到享元对象。三.享元模式的结构Flyweight抽象享元类定义对象共享的接口通常是轻量化接口操作接收外部状态作为参数。ConcreteFlyweight具体享元类实现抽象享元类存储对象的内部状态可共享。UnsharedConcreteFlyweight非共享享元类不需要共享的对象即使细粒度也不做共享。FlyweightFactory享元工厂类维护享元对象池哈希容器管理享元对象的创建与复用。Client客户端维护外部状态调用享元对象把外部状态传入享元接口。四.享元模式的优缺点优点减少大量重复对象创建显著节省内存。提高性能尤其系统存在大量细粒度相似对象时。缺点增加系统复杂度需要区分、分离内部状态与外部状态。外部状态由客户端维护必须保证外部状态传入正确否则业务逻辑出错。五.享元模式的 C 实现场景森林中大量树木树种名称、颜色、纹理 内部状态享元共享每棵树的坐标x、y 外部状态客户端维护。相同树种只创建一份TreeType对象多棵树持有这个共享对象各自保存自己的位置。#includeiostream#includeunordered_map#includestring#includememoryusingnamespacestd;// Flyweight抽象享元类classTreeType{protected:string name;// 内部状态树名称string color;// 内部状态颜色string texture;// 内部状态纹理public:TreeType(conststringname,conststringcolor,conststringtexture):name(name),color(color),texture(texture){}// 操作接口x,y为传入的外部状态virtualvoidDisplay(intx,inty)const0;virtual~TreeType()default;};// ConcreteFlyweight具体享元类存储内部状态classConcreteTreeType:publicTreeType{public:ConcreteTreeType(conststringname,conststringcolor,conststringtexture):TreeType(name,color,texture){}voidDisplay(intx,inty)constoverride{coutTree [Type: name, Color: color, Texture: texture] at (x, y)endl;}};// FlyweightFactory享元工厂维护享元池classTreeFactory{private:unordered_mapstring,shared_ptrTreeTypetreeTypes;// 对象池public:shared_ptrTreeTypeGetTreeType(conststringname,conststringcolor,conststringtexture){// 拼接key根据内部状态生成唯一键string keyname_color_texture;if(treeTypes.find(key)treeTypes.end()){// 池中没有则新建享元对象放入池treeTypes[key]make_sharedConcreteTreeType(name,color,texture);coutCreated new TreeType: keyendl;}returntreeTypes[key];// 返回共享对象}};// 客户端辅助类 Tree持有享元对象保存外部状态 x,yclassTree{private:shared_ptrTreeTypetype;// 共享享元对象intx,y;// 外部状态坐标每个树自己独有public:Tree(intx,inty,shared_ptrTreeTypetype):x(x),y(y),type(type){}voidDisplay()const{type-Display(x,y);// 将外部状态传给享元对象执行}};// 主函数客户端intmain(){TreeFactory factory;// 创建多棵树部分树种会复用享元对象shared_ptrTreetree1make_sharedTree(10,20,factory.GetTreeType(Oak,Green,Smooth));shared_ptrTreetree2make_sharedTree(15,25,factory.GetTreeType(Pine,Dark Green,Rough));shared_ptrTreetree3make_sharedTree(10,20,factory.GetTreeType(Oak,Green,Smooth));// 复用Oak对象// 打印树信息tree1-Display();tree2-Display();tree3-Display();return0;}C运行输出Created new TreeType: Oak_Green_Smooth Created new TreeType: Pine_Dark Green_Rough Tree [Type: Oak, Color: Green, Texture: Smooth] at (10, 20) Tree [Type: Pine, Color: Dark Green, Texture: Rough] at (15, 25) Tree [Type: Oak, Color: Green, Texture: Smooth] at (10, 20)可以看到Oak只创建1次tree1、tree3共用同一个享元对象实例。六.享元模式的 Java 实现importjava.util.HashMap;importjava.util.Map;// Flyweight抽象享元类abstractclassTreeType{protectedStringname;protectedStringcolor;protectedStringtexture;publicTreeType(Stringname,Stringcolor,Stringtexture){this.namename;this.colorcolor;this.texturetexture;}publicabstractvoiddisplay(intx,inty);}// ConcreteFlyweight 具体享元classConcreteTreeTypeextendsTreeType{publicConcreteTreeType(Stringname,Stringcolor,Stringtexture){super(name,color,texture);}Overridepublicvoiddisplay(intx,inty){System.out.println(Tree [Type: name, Color: color, Texture: texture] at (x, y));}}// FlyweightFactory享元工厂classTreeFactory{privateMapString,TreeTypetreeTypesnewHashMap();publicTreeTypegetTreeType(Stringname,Stringcolor,Stringtexture){Stringkeyname_color_texture;if(!treeTypes.containsKey(key)){treeTypes.put(key,newConcreteTreeType(name,color,texture));System.out.println(Created new TreeType: key);}returntreeTypes.get(key);}}// 客户端辅助类持有外部状态classTree{privateTreeTypetype;privateintx,y;publicTree(intx,inty,TreeTypetype){this.xx;this.yy;this.typetype;}publicvoiddisplay(){type.display(x,y);}}// 客户端publicclassFlyweightPatternDemo{publicstaticvoidmain(String[]args){TreeFactoryfactorynewTreeFactory();Treetree1newTree(10,20,factory.getTreeType(Oak,Green,Smooth));Treetree2newTree(15,25,factory.getTreeType(Pine,Dark Green,Rough));Treetree3newTree(10,20,factory.getTreeType(Oak,Green,Smooth));tree1.display();tree2.display();tree3.display();}}七.代码解析TreeType / ConcreteTreeType享元角色TreeType抽象享元定义接口内部状态name、color、texture保存在具体享元对象中一旦创建不会修改。Display(x,y)不保存坐标坐标作为外部状态参数传入这是享元关键享元对象不能存储外部可变数据。TreeFactory享元工厂使用哈希unordered_map作为对象池根据内部状态拼接keykey存在直接返回旧对象不存在就新建放入池所有共享对象统一由工厂获取客户端不能直接new具体享元。Tree客户端辅助Tree保存独有的外部状态x、y持有共享的享元对象指针业务调用时把自己的外部状态传给享元对象。运行现象相同key只会打印一次Created new TreeType代表对象只实例化一次多处复用。八.总结享元模式核心区分内部状态不变放享元对象共享和外部状态变化客户端维护传入工厂做对象池缓存复用细粒度对象节约内存。应用场景游戏大量重复图形元素树木、怪物模板位置是外部状态文本编辑器字符对象字体样式内部状态字符位置外部状态连接池数据库连接池、对象池复用昂贵对象。关键点归属结构型设计模式别名轻量级模式。五大角色抽象享元Flyweight、具体享元ConcreteFlyweight、非共享享元UnsharedConcreteFlyweight、享元工厂FlyweightFactory、客户端Client。核心内部状态可共享外部状态客户端传入享元对象不存外部状态。适合系统存在大量细粒度相似对象不适合对象数量少状态复杂多变。对比区分享元模式是对象池/缓存复用对象省内存单例是全局只允许一个实例两者意图不一样。