设计模式的熟练掌握,能够更容易理解系统的底层架构实现。
一、什么是享元模式
享元模式(Flyweight Pattern):以共享的方式高效的支持大量的细粒度对象。通过复用内存中已存在的对象,降低系统创建对象实例的性能消耗。
享元的英文是Flyweight,是一个来自体育方面的专业用语,在拳击、摔跤和举重比赛中特指最轻量的级别。把这个单词移植到软件工程中,也是用来表示特别小的对象,即细粒度的对象。至于为什么把Flyweight翻译为“享元”,可以理解为共享元对象,也就是共享细粒度对象。
在面向对象中,大量细粒度对象的创建、销毁及存储所造成的资源和性能上的损耗,可能会在系统运行时形成瓶颈。那么该如何避免产生大量的细粒度对象,同时又不影响系统使用面向对象的方式进行操作呢?享元模式提供了一个比较好的解决方案。
二、享元模式几个角色
uml类图:
抽象享元类(Flyweight)
它是所有具体享元类的超类。为这些类规定出需要实现的公共接口,那些需要外蕴状态(Exte的操作可以通过方法的参数传入。抽象享元的接口使得享元变得可能,但是并不强制子类实行共享,因此并非所有的享元对象都是可以共享的。
具体享元类(FlyWeightAIml,FlyWeightBIml)
具体享元类实现了抽象享元类所规定的接口。如果有内蕴状态的话,必须负责为内蕴状态提供存储空间。享元对象的内蕴状态必须与对象所处的周围环境无关,从而使得享元对象可以在系统内共享。有时候具体享元类又称为单纯具体享元类,因为复合享元类是由单纯具体享元角色通过复合而成的。
享元工厂类(FlyweightFactoiy)
享元工厂类负责创建和管理享元对象。当一个客户端对象请求一个享元对象的时候,享元工厂需要检查系统中是否已经有一个符合要求的享元对象,如果已经有了,享元工厂角色就应当提供这个已有的享元对象;如果系统中没有适当的享元对象的话,享元工厂角色就应当创建一个新的合适的享元对象。
客户类(Client)
客户类需要自行存储所有享元对象的外蕴状态。
三、享元模式使用场景
当系统中某个对象类型的实例较多的时候;
当系统设计时候,对象实例真正有区别的分类很少,例如对于拼音,如果对每个字母都初始化一个对象实例的话,这样实例就太多了。使用享元模式只需要提前初始化基本拼音,就可以任意进行组装成不同的拼音
四、代码分析
网上很多例子,看着不太明白。使用字母进行举例子通俗易懂。
CharactorFactory 工厂
package Chartflyweight;
import java.util.Hashtable;
public class CharactorFactory {
private Hashtable<String, FlyWeight> charactors = new Hashtable<String, FlyWeight>();
// 构造函数
public CharactorFactory() {
charactors.put("A", new FlyWeightAIml());
charactors.put("B", new FlyWeightBIml());
}
// 获得指定字符实例
public FlyWeight getCharactor(String key) {
FlyWeight charactor = (FlyWeight) charactors.get(key);
if (charactor == null) {
if (key.equals("A")) {
charactor = new FlyWeightAIml();
} else if (key.equals("B")) {
charactor = new FlyWeightBIml();
}
charactors.put(key, charactor);
}
return charactor;
}
}
FlyWeight 享元抽象类
package Chartflyweight;
public abstract class FlyWeight {
protected String charStr = "";
protected int fontSize;
protected abstract void operator(int fontSize);
// 显示方法
protected abstract void displayCharator();
}
FlyWeightAIml 具体实现类
package Chartflyweight;
public class FlyWeightAIml extends FlyWeight {
@Override
protected void operator(int fontSize) {
this.fontSize=fontSize;
}
public FlyWeightAIml() {
this.charStr = "A";
this.fontSize=12;
}
@Override
protected void displayCharator() {
System.out.println("字符:" + this.charStr + ",大小:" + fontSize);
}
}
FlyWeightBIml 具体实现类
package Chartflyweight;
public class FlyWeightBIml extends FlyWeight {
@Override
protected void operator(int fontSize) {
this.fontSize = fontSize;
}
public FlyWeightBIml() {
this.charStr = "B";
this.fontSize = 12;
}
@Override
protected void displayCharator() {
System.out.println("字符:" + this.charStr + ",大小:" + fontSize);
}
}
Client 测试类 1 ( 简单的剔除外蕴状态,在client中进行存储)
package Chartflyweight;
//如何有特别多的外部状态,则需要很多的函数,函数进行抽取
public class Clinet {
public static void main(String[] args) {
FlyWeightAIml a = new FlyWeightAIml();
FlyWeightBIml b = new FlyWeightBIml();
// 显示字符A
display(a, 12);
// 显示字符B
display(b, 14);
}
// 设置字符的大小
public static void display(FlyWeight objChar, int nSize) {
try {
System.out.println("字符:" + objChar.charStr + ",大小:" + nSize);
} catch (Exception err) {
}
}
}
测试类2 (考虑到复用性,将外蕴状态作为参数在使用时候进行传递)
package Chartflyweight;
//如何有特别多的外部状态,则需要很多的函数,函数进行抽取
public class Clinet2 {
public static void main(String[] args) {
FlyWeightAIml a = new FlyWeightAIml();
FlyWeightBIml b = new FlyWeightBIml();
// 设置字符A的大小
a.operator(12);
// 显示字符B
a.displayCharator();
// 设置字符B的大小
b.operator(14);
// 显示字符B
b.displayCharator();
}
}
输出结果:
字符:A,大小:12
字符:B,大小:14
上面代码内蕴共享对象是 A,B ,而外蕴不共享状态是 fontSize.
引用个例子:
享元模式在一般的项目开发中并不常用,而是常常应用于系统底层的开发,以便解决系统的性能问题。
Java和.Net中的String类型就是使用了享元模式。如果在Java或者.NET中已经创建了一个字符串对象s1,那么下次再创建相同的字符串s2的时候,系统只是把s2的引用指向s1所引用的具体对象,这就实现了相同字符串在内存中的共享。如果每次执行s1=“abc”操作的时候,都创建一个新的字符串对象的话,那么内存的开销会很大。
如果大家有兴趣的话,可以用下面的程序进行测试,就会知道s1和s2的引用是否一致:
Java代码:
String s1 = "测试字符串1";
String s2 = "测试字符串1";
//“==”用来判断两个对象是否是同一个,equals判断字符串的值是否相等
if( s1 == s2 ){
System.out.println("两者一致");
}else{
System.out.println("两者不一致");
}
程序运行后,输出的结果为“两者一致”,这说明String类的设计采用了享元模式。如果s1的内容发生了变化,比如执行了s1 += “变化”的语句,那么s1与s2的引用将不再一致。
Java DEMO :http://pan.baidu.com/s/1bpKhdpl
引用:
享元(Flyweight)模式 http://www.cnblogs.com/zhenyulu/articles/55793.html
设计模式之享元模式 http://blog.csdn.net/wanghao72214/article/details/4046182
Flyweight模式的学习 http://supercrsky.iteye.com/blog/372714