享元模式(Flyweight Pattern):运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。由于享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻量级模式,它是一种对象结构型模式。
Flyweight在拳击比赛中指最轻量级,即"蝇量级",有些作者翻译为"羽量级"。这里使用"享元模式"更能反映模式的用意。
享元模式以共享的方式高效地支持大量的细粒度对象。享元对象能做到共享的关键是区分内蕴状态(Internal State)和外蕴状态(External State)。内蕴状态是存储在享元对象内部并且不会随环境改变而改变。因此内蕴状态并可以共享。
外蕴状态是随环境改变而改变的、不可以共享的状态。享元对象的外蕴状态必须由客户端保存,并在享元对象被创建之后,在需要使用的时候再传入到享元对象内部。外蕴状态与内蕴状态是相互独立的。
享元模式的应用
享元模式在编辑器系统中大量使用。一个文本编辑器往往会提供很多种字体,而通常的做法就是将每一个字母做成一个享元对象。享元对象的内蕴状态就是这个字母,而字母在文本中的位置和字模风格等其他信息则是外蕴状态。比如,字母a可能出现在文本的很多地方,虽然这些字母a的位置和字模风格不同,但是所有这些地方使用的都是同一个字母对象。这样一来,字母对象就可以在整个系统中共享。
在单纯享元模式中,所有的享元对象都是可以共享的。单纯享元模式所涉及的角色如下:
抽象享元(Flyweight)角色:此角色是所有的具体享元类的超类,为这些类规定出需要实现的公共接口。那些需要外蕴状态(External State)的操作可以通过调用商业方法以参数形式传入。
具体享元(ConcreteFlyweight)角色:实现抽象享元角色所规定的接口。如果有内蕴状态的话,必须负责为内蕴状态提供存储空间。享元对象的内蕴状态必须与对象所处的周围环境无关,从而使得享元对象可以在系统内共享的。
享元工厂(FlyweightFactory)角色:本角色负责创建和管理享元角色。本角色必须保证享元对象可以被系统适当地共享。当一个客户端对象调用一个享元对象的时候,享元工厂角色会检查系统中是否已经有一个复合要求的享元对象。如果已经有了,享元工厂角色就应当提供这个已有的享元对象;如果系统中没有一个适当的享元对象的话,享元工厂角色就应当创建一个合适的享元对象。
客户端(Client)角色:本角色需要维护一个对所有享元对象的引用。本角色需要自行存储所有享元对象的外蕴状态。
public class FlyweightFactory { private static HashMap flyweights = new HashMap(); public static Flyweight getFlyweight(String key) { if(flyweights.containsKey(key)) { return (Flyweight)flyweights.get(key); } else { Flyweight fw = new ConcreteFlyweight(); flyweights.put(key,fw); return fw; } } } public class Flyweight { private String intrinsicState; public Flyweight(String intrinsicState) { this.intrinsicState=intrinsicState; } public void operation(String extrinsicState) { ...... } }代码二、
public interface NetworkDevice { public String getType(); public void use(); }具体享元角色
public class Hub implements NetworkDevice { private String type; public Hub(String type) { this.type=type; } public String getType() { return this.type; } public void use() { System.out.println("Linked by Hub, type is " + this.type); } }
public class Switch implements NetworkDevice { private String type; public Switch(String type) { this.type=type; } public String getType() { return this.type; } public void use() { System.out.println("Linked by switch, type is " + this.type); } }享元工厂角色
import java.util.*; public class DeviceFactory { private ArrayList devices = new ArrayList(); private int totalTerminal=0; public DeviceFactory() { NetworkDevice nd1=new Switch("Cisco-WS-C2950-24"); devices.add(nd1); NetworkDevice nd2=new Hub("TP-LINK-HF8M"); devices.add(nd2); } public NetworkDevice getNetworkDevice(String type) { if(type.equalsIgnoreCase("cisco")) { totalTerminal++; return (NetworkDevice)devices.get(0); } else if(type.equalsIgnoreCase("tp")) { totalTerminal++; return (NetworkDevice)devices.get(1); } else { return null; } } public int getTotalDevice() { return devices.size(); } public int getTotalTerminal() { return totalTerminal; } }客户端角色
public class Client { public static void main(String args[]) { NetworkDevice nd1,nd2,nd3,nd4,nd5; DeviceFactory df=new DeviceFactory(); nd1=df.getNetworkDevice("cisco"); nd1.use(); nd2=df.getNetworkDevice("cisco"); nd2.use(); nd3=df.getNetworkDevice("cisco"); nd3.use(); nd4=df.getNetworkDevice("tp"); nd4.use(); nd5=df.getNetworkDevice("tp"); nd5.use(); System.out.println("Total Device:" + df.getTotalDevice()); System.out.println("Total Terminal:" + df.getTotalTerminal()); } }
public class Demo
{
public static void main(String args[])
{
String str1 = "abcd";
String str2 = "abcd";
String str3 = "ab" + "cd";
String str4 = "ab";
str4 += "cd";
System.out.println(str1 == str2);
System.out.println(str1 == str3);
System.out.println(str1 == str4);
}
}