享元模式是对象的结构模式。享元模式的意图是通过共享高效地支持大量细粒度的对象,是让多个客户对象间共享访问限定数量的对象,享元对象能做到共享的关键是区分内蕴状态(Internal State)和外蕴状态(External State)。
内蕴状态(Internal State)是存储在享元对象内部的,并且是不会随环境的改变而有所不同。因此,一个享元可以具有内蕴状态并可以共享。
外蕴状态(External State)是随环境的改变而改变的、不可以共享的。享元对象的外蕴状态必须由客户端保存,并在享元对象被创建之后,在需要使用的时候再传入到享元对象内部。外蕴状态不可以影响享元对象的内蕴状态,它们是相互独立的。
享元模式的UML图如下:
以前在托管行工作,托管行申请做场内业务时,中登会提供自己的银行账户,供场内业务资金划付。中登解释说,我们有16家银行供您选择,您可以根据自己的需要选择合适的账户划款。
这里所说的16家银行,其实就相当于一个”账户池“,不同的托管行来申请账户时,中登先到自己的池子中找到对应的账户(银行卡),给托管行分配下去。那么可以想象在中登的内部账户池子里,肯定要提取出来账户的哪些信息是可以共享的,哪些信息是随着客户的变化而发生改变的。提取出来的“共享”信息,可以定期存入池子,供后续客户共享。非共享的信息实时分配更新。
根据上述描述,假设银行卡可共享的信息有名称、颜色、卡的尺寸等,不可共享的信息是银行的各个分行,会根据托管行所在的位置不同而不同。
在这里,我先定义两个Enum类:Bank和Color:
package com.pattern.pub;
public enum Bank {
ABC("中国农业银行"),
CCB("中国建设银行"),
BOC("中国银行"),
ICBC("中国工商银行"),
CEB("中国光大银行"),
PBC("中国人民银行"),
CMB("招商银行"),
BCM("交通银行");
private String name;
private Bank(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package com.pattern.pub;
public enum Color {
RED("红色"),GREEN("绿色"),WHITE("白色"),BLACK("黑色"),YELLOW("黄色"),BLUE("蓝色");
private String colorName;
private Color(String name){
this.colorName=name;
}
public String getColorName() {
return colorName;
}
public void setColorName(String colorName) {
this.colorName = colorName;
}
}
抽象出银行卡的内部属性和外部属性,分别定义成实体类,其中内部实体类为了实现可共享,需要重写hashCode()和equals(Object obj)方法:
package com.pattern.flyweight;
import com.pattern.pub.Color;
/**
* 银行卡的内部属性-实体类
* @author
*
*/
public class CardInternalState {
private String name;
private Color color;
private final Float height=53.98f;
private final Float width=85.6f;
public CardInternalState(String name, Color color) {
super();
this.name = name;
this.color = color;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
public Float getHeight() {
return height;
}
public Float getWidth() {
return width;
}
@Override
public String toString() {
return "Card [name=" + name + ", color=" + color + ", height=" + height + ", width=" + width + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((color == null) ? 0 : color.hashCode());
result = prime * result + ((height == null) ? 0 : height.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((width == null) ? 0 : width.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
CardInternalState other = (CardInternalState) obj;
if (color != other.color)
return false;
if (height == null) {
if (other.height != null)
return false;
} else if (!height.equals(other.height))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (width == null) {
if (other.width != null)
return false;
} else if (!width.equals(other.width))
return false;
return true;
}
}
package com.pattern.flyweight;
/**
* 外部属性-实体类
* @author
*
*/
public class CardExternalState {
private String bankname;//所属分行
public String getBankname() {
return bankname;
}
public void setBankname(String bankname) {
this.bankname = bankname;
}
}
定义享元模式的接口:
package com.pattern.flyweight;
/**
* 享元接口
* @author
*
*/
public interface CardFlyweight {
public void distribution(CardInternalState card);
}
可共享的享元实现类和不可共享的实现类:
package com.pattern.flyweight;
public class CardConcreteFlyweight implements CardFlyweight {
@Override
public void distribution(CardInternalState card) {
System.out.println("分配银行卡--可共享的属性哈!");
}
}
package com.pattern.flyweight;
public class CardNotConcreteFlyweight implements CardFlyweight {
@Override
public void distribution(CardInternalState card) {
System.out.println("分配银行卡--不可共享的属性嘞!");
}
}
定义享元工厂,来管理享元对象的创建和共享:
package com.pattern.flyweight;
import java.util.HashMap;
import java.util.Map;
public class CardFlyweightFactory {
private Map cardPool=new HashMap();
public CardFlyweight getFlyweight(CardInternalState card){
CardFlyweight cardFly=cardPool.get(card);
if(cardFly==null){
cardFly=new CardConcreteFlyweight();
cardPool.put(card, cardFly);
System.out.println("卡入池了入池了-------"+card.getName()+":"+card.getColor().getColorName()+"\n");
}
return cardFly;
}
public int getSize(){
return this.cardPool.size();
}
}
客户端测试类:
package com.pattern.flyweight;
import com.pattern.pub.Bank;
import com.pattern.pub.Color;
public class Test {
public static void main(String[] args) {
CardFlyweightFactory factory=new CardFlyweightFactory();
for(int i=0;i<100000;i++){//模拟有100000*8个客户要分配卡片
CardInternalState state0=new CardInternalState(Bank.ABC.getName(),Color.GREEN);
CardFlyweight fly0=factory.getFlyweight(state0);
CardInternalState state5=new CardInternalState(Bank.CCB.getName(),Color.GREEN);
CardFlyweight fly5=factory.getFlyweight(state5);
CardInternalState state3=new CardInternalState(Bank.CCB.getName(),Color.GREEN);
CardFlyweight fly3=factory.getFlyweight(state3);
CardInternalState state1=new CardInternalState(Bank.CCB.getName(),Color.BLUE);
CardFlyweight fly1=factory.getFlyweight(state1);
CardInternalState state2=new CardInternalState(Bank.CCB.getName(),Color.BLUE);
CardFlyweight fly2=factory.getFlyweight(state2);
CardInternalState state4=new CardInternalState(Bank.CCB.getName(),Color.GREEN);
CardFlyweight fly4=factory.getFlyweight(state4);
CardInternalState state6=new CardInternalState(Bank.ABC.getName(),Color.YELLOW);
CardFlyweight fly6=factory.getFlyweight(state6);
CardInternalState state7=new CardInternalState(Bank.ABC.getName(),Color.GREEN);
CardFlyweight fly7=factory.getFlyweight(state7);
}
System.out.println("池中有几种卡了呢?--------------"+factory.getSize()+"\n");
}
}
输出结果:
以上例子中,若不用享元模式,当有800000客户开立账户时,系统中会创建800000个对象,占用大量的内存空间。但是享元模式下,只创建了4个对象,实现了有效的对象共享。
可以看出,享元模式最主要有以下角色和职责:
● 抽象享元(Flyweight)角色 :一个抽象接口,规定所有具体享元角色需要实现的方法。
● 具体享元(ConcreteFlyweight)角色:实现抽象享元角色所规定出的接口。如果有内蕴状态的话,必须负责为内蕴状态提供存储空间。
● 复合享元(ConcreteCompositeFlyweight)角色 :复合享元角色所代表的对象是不可以共享的,但是一个复合享元对象可以分解成为多个本身是单纯享元对象的组合。复合享元角色又称作不可共享的享元对象。
● 享元工厂(FlyweightFactory)角色 :负责创建和管理享元角色。本角色必须保证享元对象可以被系统适当地共享。当一个客户端对象调用一个享元对象的时候,享元工厂角色会检查系统中是否已经有 一个符合要求的享元对象。如果已经有了,享元工厂角色就应当提供这个已有的享元对象;如果系统中没有一个适当的享元对象的话,享元工厂角色就应当创建一个 合适的享元对象。
享元模式的优缺点:
享元模式的优点在于它大幅度地降低内存中对象的数量。但是,它做到这一点所付出的代价也是很高的:
● 享元模式使得系统更加复杂。为了使对象可以共享,需要将一些状态外部化,这使得程序的逻辑复杂化。
● 享元模式将享元对象的状态外部化,而读取外部状态使得运行时间稍微变长。
在JAVA中,享元模式的应用是非常普遍的,比如线程池,数据库连接池,String类等。
源码下载:http://download.csdn.net/download/pelifymeng2/9994734