查看“设计模式:享元模式”的源代码
←
设计模式:享元模式
跳到导航
跳到搜索
因为以下原因,您没有权限编辑本页:
您请求的操作仅限属于该用户组的用户执行:
用户
您可以查看和复制此页面的源代码。
[[category:设计模式]] == 关于 == <pre> 在面向对象程序设计过程中,有时会面临要创建大量相同或相似对象实例的问题。创建那么多的对象将会耗费很多的系统资源,它是系统性能提高的一个瓶颈。 例如,围棋和五子棋中的黑白棋子,图像中的坐标点或颜色,局域网中的路由器、交换机和集线器,教室里的桌子和凳子等。这些对象有很多相似的地方,如果能把它们相同的部分提取出来共享,则能节省大量的系统资源,这就是享元模式的产生背景。 </pre> 享元(Flyweight)模式的定义:'''运用共享技术来有效地支持大量细粒度对象的复用'''。【将相同的部分提取出来复用】 * 它通过共享已经存在的对象来大幅度减少需要创建的对象数量、避免大量相似类的开销,从而提高系统资源的利用率。 === 优点和缺点 === 优点: * '''相同对象只要保存一份''',这降低了系统中对象的数量,从而降低了系统中细粒度对象给内存带来的压力。 缺点: * 为了使对象可以共享,需要将一些不能共享的状态外部化,这将增加程序的复杂性。 * 读取享元模式的外部状态会使得运行时间稍微变长。 === 应用场景 === 当系统中多处需要同一组信息时,可以把这些信息封装到一个对象中,然后对该对象进行缓存,这样,一个对象就可以提供给多出需要使用的地方,避免大量同一对象的多次创建,降低大量内存空间的消耗。 享元模式其实是工厂方法模式的一个改进机制,享元模式同样要求创建一个或一组对象,并且就是通过工厂方法模式生成对象的,只不过享元模式为工厂方法模式增加了缓存这一功能。 享元模式是通过减少内存中对象的数量来节省内存空间的,所以以下几种情形适合采用享元模式: * 系统中存在大量相同或相似的对象,这些对象耗费大量的内存资源。 * 大部分的对象可以按照内部状态进行分组,且可将不同部分外部化,这样每一个组只需保存一个内部状态。 * 由于享元模式需要额外维护一个保存享元的数据结构,所以应当在有足够多的享元实例时才值得使用享元模式。 == 结构与实现 == 享元模式的定义提出了两个要求,细粒度和共享对象。因为要求细粒度,所以不可避免地会使对象数量多且性质相近,此时我们就将这些对象的信息分为两个部分: # '''内部状态''':指对象共享出来的信息,存储在享元信息内部,并且不回随环境的改变而改变; # '''外部状态''':指对象得以依赖的一个标记,随环境的改变而改变,不可共享。 比如,连接池中的连接对象,保存在连接对象中的用户名、密码、连接URL等信息,在创建对象的时候就设置好了,不会随环境的改变而改变,这些为内部状态。而当每个连接要被回收利用时,我们需要将它标记为可用状态,这些为外部状态。 享元模式的本质是缓存共享对象,降低内存消耗。 === 结构 === 享元模式的主要角色如下: # '''抽象享元'''(Flyweight)角色:是所有的具体享元类的基类,为具体享元规范需要实现的公共接口,非享元的外部状态以参数的形式通过方法传入。 # '''具体享元'''(Concrete Flyweight)角色:实现抽象享元角色中所规定的接口。 # '''非享元'''(Unsharable Flyweight)角色:是不可以共享的外部状态,它以参数的形式注入具体享元的相关方法中。 # '''享元工厂'''(Flyweight Factory)角色:负责创建和管理享元角色。当客户对象请求一个享元对象时,享元工厂检査系统中是否存在符合要求的享元对象,如果存在则提供给客户;如果不存在的话,则创建一个新的享元对象。 其结构如下: : [[File:设计模式:享元模式.png|600px]] 其中: * 抽象享元角色,里面包含了享元方法“operation(UnsharedConcreteFlyweight state)”,'''非享元的外部状态以参数的形式通过该方法传入'''; * 客户角色通过享元工厂获取具体享元,并访问具体享元的相关方法。 === 实现 === 其代码如下: : <syntaxhighlight lang="java" line highlight="3"> //抽象享元角色 interface Flyweight { public void operation(UnsharedConcreteFlyweight state); } //具体享元角色 class ConcreteFlyweight implements Flyweight { private String key; ConcreteFlyweight(String key) { this.key = key; System.out.println("具体享元" + key + "被创建!"); } public void operation(UnsharedConcreteFlyweight outState) { System.out.print("具体享元" + key + "被调用,"); System.out.println("非享元信息是:" + outState.getInfo()); } } //非享元角色 class UnsharedConcreteFlyweight { private String info; UnsharedConcreteFlyweight(String info) { this.info = info; } public String getInfo() { return info; } public void setInfo(String info) { this.info = info; } } //享元工厂角色 class FlyweightFactory { private HashMap<String, Flyweight> flyweights = new HashMap<String, Flyweight>(); public Flyweight getFlyweight(String key) { Flyweight flyweight = (Flyweight) flyweights.get(key); if (flyweight != null) { System.out.println("具体享元" + key + "已经存在,被成功获取!"); } else { flyweight = new ConcreteFlyweight(key); flyweights.put(key, flyweight); } return flyweight; } } public class FlyweightPattern { public static void main(String[] args) { FlyweightFactory factory = new FlyweightFactory(); Flyweight f01 = factory.getFlyweight("a"); Flyweight f02 = factory.getFlyweight("a"); Flyweight f03 = factory.getFlyweight("a"); Flyweight f11 = factory.getFlyweight("b"); Flyweight f12 = factory.getFlyweight("b"); f01.operation(new UnsharedConcreteFlyweight("第1次调用a。")); f02.operation(new UnsharedConcreteFlyweight("第2次调用a。")); f03.operation(new UnsharedConcreteFlyweight("第3次调用a。")); f11.operation(new UnsharedConcreteFlyweight("第1次调用b。")); f12.operation(new UnsharedConcreteFlyweight("第2次调用b。")); } } </syntaxhighlight> : <syntaxhighlight lang="java" highlight=""> 具体享元a被创建! 具体享元a已经存在,被成功获取! 具体享元a已经存在,被成功获取! 具体享元b被创建! 具体享元b已经存在,被成功获取! 具体享元a被调用,非享元信息是:第1次调用a。 具体享元a被调用,非享元信息是:第2次调用a。 具体享元a被调用,非享元信息是:第3次调用a。 具体享元b被调用,非享元信息是:第1次调用b。 具体享元b被调用,非享元信息是:第2次调用b。 </syntaxhighlight> == 模式的扩展 == 在实际使用过程中,存在两种特殊的享元模式: # '''单纯享元'''模式: #: 这种享元模式中的所有的具体享元类都是可以共享的,不存在非共享的具体享元类;【无“非享元角色”】 #: [[File:设计模式:享元模式:单纯享元模式.png|400px]] # '''复合享元'''模式: #: 这种享元模式中的有些享元对象是由一些单纯享元对象组合而成的,它们就是复合享元对象;【“具体享元角色”是多个“单纯享元”的组合】 #* 虽然复合享元对象本身不能共享,但它们可以分解成单纯享元对象再被共享。 #: [[File:设计模式:享元模式:复合享元模式.png|500px]]
返回至“
设计模式:享元模式
”。
导航菜单
个人工具
登录
命名空间
页面
讨论
大陆简体
已展开
已折叠
查看
阅读
查看源代码
查看历史
更多
已展开
已折叠
搜索
导航
首页
最近更改
随机页面
MediaWiki帮助
笔记
服务器
数据库
后端
前端
工具
《To do list》
日常
阅读
电影
摄影
其他
Software
Windows
WIKIOE
所有分类
所有页面
侧边栏
站点日志
工具
链入页面
相关更改
特殊页面
页面信息