享元模式——Flyweight
1. 概念
享元模式 (Flyweight ,轻量级选手 ) 就是利用可共享对象的池。因而,通常用到 Factory ,称为 Flyweight Factory 享元工厂 。 (Sam)
将对象定义为不可变 (immutable) 的是避免客户代码之间相互影响最简单方法, Java 语言中最常见的不可变对象 是 String 类对象 (public final class String{...}) 。在 Oozinoz 公司的例子中,化学物 Substance_Before 类对象中包含两种类型的属性——可变部分 ( 重量等 )& 不可变部分 ( 原子量,名称,化学式 ) ,我们将不变部分抽象 为另一个类 Chemical ,从而将 Substance_Before 改造为 Substance_After 。这样,当系统中 Substance 对象很多时,不必为每个对象维护众多的不变部分信息 ( 可以共享少量 Chemical 实例 ) 。
因此,享元模式使用 的过程实际上是个源码重构 的过程,可以在最终的代码中看不出享元的痕迹(例如 BorderFactory 类),看起来很像 Factory 模式。
然而,将对象的不可变部分提取出来仅是使用享元模式的前面一半工作。后一半工作是创建一个享元工厂 Chemical_Factory ,用于实例化享元,并组织共享享元的客户代码。另外,为了保证客户代码使用享元工厂获取享元,而非自己创建,可以限定 Chemical 的可见性:将 Chemical 作为 Chemical Factory 的内部类 。
举例: BorderFactory 是典型的 Flyweight Factory :
javax.swing.BorderFactory - Factory class for vending(vt. vi. 出售,贩卖 ) standard Border objects. Wherever possible, this factory will hand out( 分发;施舍;把…拿出来 ) references to shared Border instances.
javax.swing.Border - Provides classes and interfaces for drawing specialized borders around a Swing component.
public class BorderFactory{
final static Border emptyBorder=new EmptyBorder(0,0,0,0);
public static Border createEmptyBorder(){ return emptyBorder;}
}
2. 享元模式使用:
将 Substance_Before 重构为 Substance_After&Chemical ;
但为了保证客户代码用享元工厂获取享元对象,在 Substance_After 中编写 ChemicalImpl( 实现 Chemical 接口,这样方便从 Substance_After 中引用到接口 ) 。
public class Substance_Before {
/*
* 可变部分
*/
private double grams ; /* 重量 i.e. 75g*/
/*
* 不可变部分
*/
private String name ; /* 化学名称 i.e. Saltpeter */
private String symbol ; /* 化学式 i.e. KNO3*/
private double atomicWeight ; /* 原子量 i.e. 101*/
public double getMoles (){
return grams / atomicWeight ;
}
}
*****************************************************************
使用享元模式重构后:
public class Substance_After {
/*
* 可变部分
*/
private double grams ;
/*
* 不可变部分
* 抽象为类 Chemical 对象 !
* 好处:当 Substance_After 对象很多时,可以引用少量的
* Chemical 实例;而不必自身维护大量不变部分信息。
*/
private Chemical chemical ; /* 使用接口来访问不变对象 */
public double getMoles(){
return grams / chemical .getAtomicWeight();
}
}
public class Chemical_Factory {
private static Map chemicals = new HashMap ();
static {
chemicals .put( "carbon" , new ChemicalImpl( "Carbon" , "C" ,22)) ;
chemicals .put( "sulfur" , new ChemicalImpl( "Sulfur" , "S" ,32)) ;
chemicals .put( "saltpeter" , new ChemicalImpl( "Saltpeter" , "KNO3" ,101)) ;
}
/*
* 1. static 修饰类时只能用于内部类,不能用于普通类
* 2. static 内部类中的 static 成员(类成员)和对象成员都作为对象成员使用 !
*/
private static class ChemicalImpl implements Chemical {
private String name ; /* 化学名称 i.e. Saltpeter */
private String symbol ; /* 化学式 i.e. KNO3*/
private double atomicWeight ; /* 原子量 i.e. 101*/
private ChemicalImpl(String name,String symbol, double atomicWeight){
this . name =name;
this . symbol =symbol;
this . atomicWeight =atomicWeight;
}
public double getAtomicWeight() {
return atomicWeight ;
}
public String getName() {
return name ;
}
public String getSymbol() {
return symbol ;
}
}
public static Chemical getChemical(String name){
return (Chemical) chemicals .get(name.toLowerCase());
}
}
public interface Chemical
{
String getName();
String getSymbol();
double getAtomicWeight();
}
采用享元模式后,客户端调用方法:
public class Main {
public static void main(String[] args) {
Substance_After s1=new Substance_After(75,Chemical_Factory.getChemical("SALTPETER"));
Substance_After s2=new Substance_After(150,Chemical_Factory.getChemical("saltpeter"));
System.out.println(s1.getMoles());
System.out.println(s2.getMoles());
}
}