- 浏览: 409216 次
- 性别:
- 来自: 秦皇岛
最新评论
-
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 1407//工厂方法模式示例: package innerclass ... -
Builder(生成器)模式
2009-05-15 21:22 1625当构造某对象时,也 ... -
责任链(Chain of Responsibility)模式
2009-05-15 21:18 1826面向对象开发 ... -
Prototype(原型)模式
2009-05-15 21:17 1491Prototype模式不通过实例化类来创建一个新的未初始化的实 ... -
Proxy(代理)模式
2009-05-15 21:14 1528Proxy(代理)模式 ... -
Mediator(中介者)模式
2009-05-15 21:14 1478通常,面向对象的软 ... -
Observer(观察者)模式一
2009-05-15 21:13 1562Observer模式的宗旨是在多个对象之间定义一对多的关系,以 ... -
责任型模式
2009-05-15 21:12 1013对象的责任类似于 ... -
Bridge(桥接模式)
2009-05-15 21:11 1420Bridge模式着重考虑如何实现对具体实现的抽象(ab ... -
Facade外观模式
2009-05-15 21:11 29041.Facade模式就是一个功能介于包和完整应用程序之 ... -
Composite(组合)模式
2009-05-15 21:07 1774Composite模式涉及的是一组对象,其中有些 ... -
Memento(备忘录)模式
2009-05-15 21:07 2203有时候,我们需要创建的对象曾经在系统中出现过。这种情形可能出现 ... -
操作型模式简介
2009-05-15 21:01 1158我们只有弄清楚诸如算法、多态性、方法和操作等术语的不同意 ... -
Template Method(模板方法)模式
2009-05-15 21:01 1081普通方法的方法体 ... -
Template Method二
2009-05-15 20:59 1233Template Method模式类似于Adapter模 ... -
State(状态)模式
2009-05-15 20:58 1441对象的状态是其属性当 ... -
Strategy(策略)模式
2009-05-15 20:55 1076算法是定义好的过程, ... -
Strategy(策略)模式二
2009-05-15 20:54 13592.重构为Strategy模式: ... -
Command(命令)模式
2009-05-15 20:52 1544让方法运行的最常见 ... -
Command模式二
2009-05-15 20:50 2150假设现有一个新需求要求我们统计方 ...
相关推荐
享元模式是面向对象设计中的一种结构型模式,它的主要目的是通过共享大量相似对象来减少内存的使用,提高系统的性能。在C#编程语言中,我们可以利用享元模式来优化那些具有大量实例但大部分状态可以共享的对象。在这...
C#面向对象设计模式纵横谈(12):Flyweight 享元模式(结构型模式)
享元模式的核心是Flyweight类,它是需要被共享的对象,通常包含两个部分:内在状态(Intrinsic State)和外在状态(Extrinsic State)。内在状态是指对象内部不变的部分,可以在多个对象之间共享;外在状态是随环境...
在这里与各位分享本人从网络上下载的C#面向对象设计模式纵横谈系列视频,共有25节,除了第一节需要各位贡献一点资源分以作为对本人上传资源的回馈,后面的其他资源均不需要... 这是第12节:结构型模式Flyweight享元模式
总结来说,FlyWeight享元模式是一种优化内存使用的设计策略,通过共享对象减少系统中对象的数量,从而提高系统效率。理解并合理运用享元模式,对于编写高效且资源友好的代码至关重要。在开发过程中,我们需要识别...
享元模式是一种设计模式,主要用于减少对象的创建,从而提高性能和降低内存占用。在C++编程中,享元模式的应用能够帮助优化内存管理和提高程序效率。享元模式的核心思想是区分对象的内部状态(intrinsic state)和...
享元模式(Flyweight Pattern)是一种结构型设计模式,它能有效地减少系统中对象的数量,从而降低内存消耗,提高性能。这种模式通过共享大量相似对象的内部状态来达到这一目标,而只保留对象的外部状态在外部管理。...
享元模式是设计模式中的一种结构型模式,它主要通过共享已有对象来减少内存中对象的数量,从而提高系统性能。在C#编程中,享元模式尤其适用于那些创建大量相似对象且内存消耗较大的场景。本篇文章将深入探讨享元模式...
享元模式(Flyweight Pattern)是一种结构型设计模式,用于减少创建大量小对象所带来的内存开销。通过共享对象,享元模式能够有效地支持大量细粒度的对象,减少内存使用并提高性能。它常用于需要大量重复对象的场景...
1. 抽象享元(Flyweight)角色: 抽象享元是享元模式的核心,定义了一个公共接口,为客户端提供了操作共享对象的途径。在Java中,这个角色通常表现为一个接口,例如`Letter`,包含所有可能的操作。 2. 具体享元...
享元模式是软件设计模式中的一种结构型模式,它的主要目的是通过共享大量细粒度对象来减少内存的使用,提高系统性能。在许多场景下,尤其是处理大量相似对象时,享元模式能显著减少内存开销。这个压缩包文件...
享元模式(Flyweight Pattern)是软件设计中的一种结构型设计模式,它通过共享技术来支持大量细粒度的对象,以此来降低内存中对象的数量。在PHP中实现享元模式,可以帮助我们优化程序性能,特别是在对象数目过多时,...
享元模式(Flyweight Pattern)是设计模式中的一种优化模式,主要用于减少创建大量相似对象所需的内存消耗。在C++程序设计中,当系统中存在大量的相同或相似的对象时,使用享元模式可以有效地降低内存占用,提高系统...
比如包括了工厂模式、Bridge桥接模式、Builder构建模式、Facade外观模式、Adapter适配器模式,Composite组合模式、Decorator装饰器模式,FactoryMethod工厂方法模式、Flyweight享元模式,Interpreter解释器模式,...
复合享元模式则引入了享元工厂(Flyweight Factory)来管理和创建享元对象。享元工厂负责管理享元对象池,并根据需要向客户端提供享元对象。当请求的对象不在池中时,工厂会创建新的享元对象;如果存在相同的内蕴...
享元模式是一种经典的设计模式,属于结构型模式,它的核心思想是通过共享已经存在的对象来减少内存中的对象数量,从而提高系统性能。在许多场景下,特别是计算机编程中,我们可能会遇到大量的相似对象,比如在图形...
在“Flyweight”这个文件中,我们可以预期找到的是一个关于享元模式的代码实现。这个文件可能包含了一个享元接口,若干个实现了该接口的具体享元类,以及一个享元工厂类。享元接口定义了对外暴露的方法,这些方法...
享元模式的核心是享元对象(Flyweight),它是一个可以被共享的类,通常包含一些共享状态(Static State)和不共享状态(External State)。共享状态是在所有享元对象之间共享的数据,它们不会因对象的不同而改变;...