- 浏览: 403908 次
- 性别:
- 来自: 秦皇岛
最新评论
-
prayjourney:
了解了,讲的不错
DataInputStream和DataOutputStream类 -
niunianss:
将字节退回的时候,需要添加判断,最后一个字符是英文时,实际数组 ...
PushbackInputStream -
cctt_1:
不要误人子弟,那根本就不是 解释器模式!!!那是Composi ...
Interpreter(解释器)模式 -
java-大神:
[i][i]引用引用引用引用[/img][/img][/img ...
BufferedReader和BufferedWriter -
百合不是茶:
你的程序在文件输入输出流中传入agrs[0]时,会报错越界 ...
DataInputStream和DataOutputStream类
Flyweight模式可实现客户代码之间的对象共享,创建共享对象的职责,这一点普通对象是不具备的。一般的对象不必关心共享职责,任何时刻最多只能有一个客户代码引用它,其他时刻可以是其他客户代码引用。如果多个客户代码引用同一个对象,那么当某个客户代码修改了该对象的状态时,该对象是不会通知其他客户代码的。然而,有时候,我们需要让多个客户代码共享访问同一个对象。
当我们必须管理成千上万个小型对象的时候,例如在线电子图书中的字符对象,我们需要让多个客户代码共享一个对象。在这种情况下,为了提高应用程序的性能,需要考虑这些细粒度的对象在多个客户代码之间的安全共享访问问题。对于在线电子图书来说,一本书只需要一个A对象,但是当出现不同的A对象时,则需要我们采取某种方法对之建模。
Flyweight模式的主要意图是:通过共享来支持大量的细粒度对象的使用效率。
1. 不变性:
Flyweight模式可让多个客户安全共享对有限数量对象的访问。为实现这个目标,我们必须考虑如果某个客户代码改变了共享对象的状态,这将会影响共享该对象的其他所有客户代码。在最普通的情况下,该对象仅被一个单独的客户代码访问,自然不存在任何问题。当多个客户代码共享访问一个对象的时候,如何避免客户代码之间的相互影响是个值得关注的问题,这个问题最简单和最常见的解决办法,便是限制客户代码调用任何可能引起共享对象状态变化的方法。在创建对象时,可以将这个对象定义为immutable类型这样该对象就不会被改变。Java语言中不可变对象是String类对象。一旦创建了一个String对象,任何客户代码都无法改变它的字符。
突破题:你是否认同Java语言设计者将String对象定义为不可变的做法,并请给出你的理由。
答:赞成方观点,主要是考虑到实际应用中,字符串通常被多个用户共享。如果字符串能够被修改,那么一个用户对字符串不经意的改动就会影响其他用户。这种问题在实际应用中经常会出现,它的根结在于字符串可能会被修改。例如,当一个方法返回一个Customer对象的客户名字符串之后,它仍然保留了对该字符串的引用。如果字符串可以被修改,那么当用户在散列表中将该字符串变成全大写的形式,Customer对象的名字也会随之改变。在Java语言中,你可以把某字符串全部大写,但必须使用新对象,而不是仅仅修改原来的对象。字符串的不变性有利于多个用户安全地共享该字符串。更进一步说,字符串的不可变性也可以防止系统出现安全危机。
反对方观点:将字符串设置为不变,这样做的确能够避免我们犯某些错误,但是其负面影响也很大。首先,即使在确实需要修改的场合,开发人员也无法修改字符串。第二,在一种计算机语言中加入特殊的规则,将会使该语言难以学习和使用。Java语言和Smalltalk语言功能一样强大,但是前者就比后者难学多了。最后,任何语言都无法避免使用者犯错误。如果一种计算机语言简单易学,使用者就能够更加深入地掌握它,这样使用者就会有更多的时间来研究如何构建和使用该语言的测试架构。
如果有大量的类似对象需要管理,也许需要共享这些对象;不过,它们可能不是不可变的。在这种情况下,我们必须先将对象的不可变部分提取出来,首先共享不变的部分。
2.提取享元中不可变的部分:
对于文档而言,字符普通存在;而对于Oozinoz公司而言,化学品到处都是。该公司的采购、工程、生产、安全等部门都在监控这成千上万的化学品在整个工厂的流动情况。经过建模,这些化学品都被描述为Substance类的实例。如下图所示:
化学品被建模为Substance类的实例
Substance类提供众多可以访问其属性的方法,另外还提供getMoles()方法用于返回该化学品的摩尔数---即分子数量。Substance对象表示化学品的摩尔数。Oozinoz公司使用Mixture类来模拟化学品的组成。黑火药由硝石粉、硫磺、碳粉等组成。这些都是Substance类的实例。
考虑到Oozinoz公司的化学原料会越来越多,因而我们决定使用Flyweight模式来对这些化学品建模,减少Substance对象的数量。为把Subsatnce对象模拟为享元,首先需要区分该类的可变部分和不可变部分。假设你决定重构Substance类,把其中不可变部分提出放入Chemical类中。
突破题:描述出被重构的Substance2类和新的不可变类,Chemical类:
该图显示Substance类的不可变属性被提取出来放到单独的类(Chemical)中
你可以把Subsance对象的不可变部分---包括化学制品的名称、化学符号以及原子量(或分子量)---放入Chemical类中。如上图所示。
Substance2类保持对Chemical对象的引用。结果Subsance2类仍旧具有与早期版本Subsance类相同的属性。从内部来讲,这些附属属性依赖于Chemical类,就像Substance2类方法演示的那样:
public double getAtomicWeight() { return chemical.getAtomicWeight(); } public double getGrams() { return grams; } public douible getMoles() { return grams/getAtomicWeight(); }
3. 共享享元:
将对象的不可变部分提取出来仅是应用Flyweight模式前面的一半工作。后一半工作是创建一个享元工厂,用于实例化享元和组织共享享元的客户代码。另外,我们必须保证各个客户代码都将使用享元工厂创建享元实例,而不能自己创建。
为了把Chemical对象变成享元,我们创建了一个用于生成化学品享元的工厂ChemicalFactory类,该类包含一个静态方法,利用该方法可以返回指定名称的化学品享元的实例。在该工厂类初始化的时候,我们创建出各种已知常用的化学品享元实例,并将它们存放在一个散列表中。下图给出了ChemicalFactory类的设计。
package com.oozinoz.chemical; import java.util.*; public class ChemicalFactory { private static Map chemicals = new HashMap(); static { chemicals.put("carbon",new Chemical("Carbon","C",12)); chemicals.put("sulfur",new Chemical("Sulfur","S",32)); chemicals.put("saltpeter",new Chemical("Saltpeter","KN03",101)); //... } public static Chemical getChemical(String name) { return (Chemical) chemicals.get(name.toLowerCase()); } }
ChemicalFactory类是返回Chemical对象的享元工厂类
ChemicalFactory类的代码使用静态的初始化方法将Chemical对象存放在散列表中:
在创建了享元化学品的工厂类之后,我们还必须采取某些措施来保证其他开发人员一定会用享元工厂类来创建享元,而不能直接实例化Chemical享元类。有一个简单的做法就是借助Chemical类的可见性。
突破题:请问如何通过设置Chemical类的可见性来防止其他开发者直接实例化Chemical类?
答:一种方式是把Chemical类构造器定义为内部方法。这种做法可以防止ChemicalFactory类实例化Chemical类。
为避免开发人员直接实例化Chemical类,可以将Chemical和ChemicalFactory放在同一个包中,并将Chemical类的构造器声明为私有的。
然而,仅通过设置可见性修饰符,还无法完全控制享元的实例化。如果要确保ChemicalFactory类是唯一可以创建Chemical类对象的类,那么可以将Chemical类定义为ChemicalFactory的内部类(使用inner修饰符来定义)。
为访问嵌套的类型,客户代码必须使用下面的表达式指定封装类型。
ChemicalFactory.Chemical c = ChemicalFactory.getChemical("saltpeter");
使用如下办法可以简化对被嵌套类的使用:将Chemical定义为接口,将嵌套类的名称定义为ChemicalImpl。Chemical接口可以指定三个访问方法,如下所示:
package com.oozinoz.chemical2; public interface Chemical { String getName(); String getSymbol(); double getAtomicWeight(); }
客户代码不直接引用内部类,所以可设置为私有,这样就保证了只有ChmicalFactory2类可访问它。
突破题:完成下面的ChemicalFactory2.java类的代码:
使用嵌套类虽然更加复杂,但是能够彻底确保只有ChemicalFactory2类可以实例化新的享元。
package com.oozinoz.chemical2; import java.util.*; public class ChemicalFactory2 { private static Map chemicals = new HashMap(); class ChemicalImpl implements Chemical { private String name; private String symbol; private double atomicWeight; ChemicalImpl( String name, String symbol, double atomicWeight){ this.name = name; this.symbol = symbol; this.atomicWeight = atomicWeight; } public String getName() { return name; } public String getSymbol() { return symbol; } public double getAtomicWeight() { return atomicWeight; } public String toString() { return name+"("+symbol+")[" + atomicWeight + "]"; } } static{ ChemicalFactory2 factory = new ChemicalFactory2(); chemicals.put("carbon",factory.new ChemicalImpl("Carbon","C",12)); chemicals.put("sulfur",factory.new ChemicalImpl("Sulfur","S",32)); chemicals.put("saltpeter",factory.new ChemicalImpl("Saltpeter","KN03",101)); //... } public static Chemical getChemical(String name) { return (Chemical) chemicals.get(name.toLowerCase()); } }
上述代码可解决三个问题:
1. ChemicalImpl嵌套类应该是私有的,保证只有ChemicalFactory2类可以使用该类。请注意嵌套类的访问范围必须是包范围,或者可以公开访问,这样包含的类可以实例化被嵌套的类。即使把构造器定义为公开访问的,如果嵌套类本身被标识为私有,则没有其他类可以使用这个构造器。
2.ChemicalFactory2构造器使用静态实例化方法,以确保本类只能创建一次化学药品列表。
3.getChemical()方法应该在类的散列表中根据名称来查找化学药品。范例代码使用小写的药品名称来存储和查找化学药品。
4.小结:
字符、化学品以及边界等对象往往会大量出现,在对它们进行建模的时候,可以使用Flyweight模式来管理对它们的共享访问。享元对象的属性必须是不可变的。为了满足这一特性,我们可以将这些对象中不可改变的部分提取出来构建成享元类。另外,为了确保享元对象能够被共享,我们还必须提供一个用于创建和查找享元对象的工厂类,并且保证客户只能使用该类来创建享元对象。设置享元类的可见性修饰符可以在某些方面帮助我们控制其他开发者对享元对象的访问,但是内部类做得更好,能够确保享元类只能被享元工厂类访问。在确保客户能够适当地使用享元工厂之后,我们就可以出色地管理对大量细粒度对象的共享访问。
发表评论
-
工厂方法模式示例
2009-11-27 14:34 1372//工厂方法模式示例: package innerclass ... -
Builder(生成器)模式
2009-05-15 21:22 1491当构造某对象时,也 ... -
责任链(Chain of Responsibility)模式
2009-05-15 21:18 1727面向对象开发 ... -
Prototype(原型)模式
2009-05-15 21:17 1439Prototype模式不通过实例化类来创建一个新的未初始化的实 ... -
Proxy(代理)模式
2009-05-15 21:14 1477Proxy(代理)模式 ... -
Mediator(中介者)模式
2009-05-15 21:14 1430通常,面向对象的软 ... -
Observer(观察者)模式一
2009-05-15 21:13 1532Observer模式的宗旨是在多个对象之间定义一对多的关系,以 ... -
责任型模式
2009-05-15 21:12 984对象的责任类似于 ... -
Bridge(桥接模式)
2009-05-15 21:11 1391Bridge模式着重考虑如何实现对具体实现的抽象(ab ... -
Facade外观模式
2009-05-15 21:11 28561.Facade模式就是一个功能介于包和完整应用程序之 ... -
Composite(组合)模式
2009-05-15 21:07 1655Composite模式涉及的是一组对象,其中有些 ... -
Memento(备忘录)模式
2009-05-15 21:07 2151有时候,我们需要创建的对象曾经在系统中出现过。这种情形可能出现 ... -
操作型模式简介
2009-05-15 21:01 1082我们只有弄清楚诸如算法、多态性、方法和操作等术语的不同意 ... -
Template Method(模板方法)模式
2009-05-15 21:01 1037普通方法的方法体 ... -
Template Method二
2009-05-15 20:59 1195Template Method模式类似于Adapter模 ... -
State(状态)模式
2009-05-15 20:58 1374对象的状态是其属性当 ... -
Strategy(策略)模式
2009-05-15 20:55 1009算法是定义好的过程, ... -
Strategy(策略)模式二
2009-05-15 20:54 13142.重构为Strategy模式: ... -
Command(命令)模式
2009-05-15 20:52 1490让方法运行的最常见 ... -
Command模式二
2009-05-15 20:50 2095假设现有一个新需求要求我们统计方 ...
相关推荐
设计模式学习笔记--Flyweight享元模式.docx设计模式学习笔记--Flyweight享元模式.docx设计模式学习笔记--Flyweight享元模式.docx设计模式学习笔记--Flyweight享元模式.docx设计模式学习笔记--Flyweight享元模式.docx
C#面向对象设计模式纵横谈(12):Flyweight 享元模式(结构型模式) (Level 300)
C#面向对象设计模式纵横谈(12):Flyweight 享元模式(结构型模式)
在这里与各位分享本人从网络上下载的C#面向对象设计模式纵横谈系列视频,共有25节,除了第一节需要各位贡献一点资源分以作为对本人上传资源的回馈,后面的其他资源均不需要... 这是第12节:结构型模式Flyweight享元模式
主要介绍了C++设计模式编程的Flyweight享元模式结构,享元模式在实现过程中主要是要为共享对象提供一个存放的"仓库"(对象池),需要的朋友可以参考下
主要介绍了Java设计模式编程中的Flyweight享元模式的开发结构,享元模式能够最大限度地重用现有的同类对象,需要的朋友可以参考下
比如包括了工厂模式、Bridge桥接模式、Builder构建模式、Facade外观模式、Adapter适配器模式,Composite组合模式、Decorator装饰器模式,FactoryMethod工厂方法模式、Flyweight享元模式,Interpreter解释器模式,...
FlyWeight享元 --- 对象结构型模式
设计模式(C#)之享元模式(Flyweight Pattern),运用共享技术有效地支持大量细粒度的对象。
C++设计模式课件13_Flyweight_享元模式.pdf
NULL 博文链接:https://hnzhoujunmei.iteye.com/blog/1033359
在享元模式中可以共享的相同内容称为内部状态(Intrinsic State),而那些需要外部...在享元模式中通常会出现工厂模式,需要创建一个享元工厂来负责维护一个享元池(Flyweight Pool)用于存储具有相同内部状态的享元对象。
享元模式英文称为“Flyweight Pattern”,我非常感谢将Flyweight Pattern翻译成享元模式的那位强人,因为这个词将这个模式使用的方式明白得表示了出来;如果翻译成为羽量级模式或者蝇量级模式等等,虽然可以含蓄的...
主要为大家详细介绍了C++设计模式之享元模式Flyweight,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。
C#面向对象设计模式纵横谈(12):Flyweight 享元模式(结构型模式) C#面向对象设计模式纵横谈(13):Proxy 代理模式(结构型模式) C#面向对象设计模式纵横谈(14):Chain of Responsibility 职责链模式(行为型模式) ...
3.6 FLYWEIGHT 享元模式 49 3.7 PROXY 代理模式 53 行为模式 57 4.1 CHAIN OF RESPONSIBILITY 职责链模式 57 4.2 COMMAND 命令模式 61 4.3 INTERPRETER 解释器模式 66 4.4 MEDIATOR 中介者模式 71 4.5 ITERATOR 迭代...
6、Flyweight 享元模式 7、Proxy 代理模式 11个行为模式: 1、Chain of Responsibility 职责链 2、Command 命令 3、Interpreter 解释器 4、Iterator 迭代器 5、Mediator 中介者 6、Memento 备忘录 7、...
com.javapatterns.flyweight 享元模式 com.javapatterns.immutable 不变模式 com.javapatterns.interfaces Java接口 com.javapatterns.interpreter 解释器模式 com.javapatterns.isp 接口隔离原则 ...