享元模式是指"运用共享技术有效地支持大量细粒度的对象"
所有"运用共享技术有效地支持大量细粒度的对象"我们可以理解为,当细粒度对象的数量过多时运行的代价相当高,此时运用共享技术可大大降低运行的代价
1.结构
1.1单纯享元模式结构
此模式,全部享元对象均可共享,如下图
(1)抽象享元角色(Flyweight):为具体享元角色规定了必须实现的方法,而外藴状态就是以参数的形式通过此方法传入,在java中科院由抽象类、接口类担当。
(2)具体享元角色(ConcreteFlyweight):实现抽象角色规定的方法.如果存在内藴状态,就扶着为内藴状态提供存储空间
(3)享元工厂角色(FlyweightFactory):负责创建和管理享元角色,要想达到共享的目的,这个角色的实现关键!(files可用HashMap或HashTable)
(4)客户端角色(client):维护对所有享元对象的引用,而且还需要存储对应的外藴状态。
1.2复合享元模式结构
此模式运用单纯享元,接口复合合成模式加以复用,如下图所示
(1)抽象享元角色(Flyweight):它是所有的具体享元类的超类
(2)具体享元角色(ConcreteFlyweight):实现抽象享元角色所规定的接口
(3)复合享元(UnsharableFlyweight):其代表的对象是不可共享的,但一个复合享元对象可愿意分解成为多个本身是单纯享元对象的组合。如上图中的ConcreteCompositeFlyweight、
(4)享元工厂角色(FlyweightFactory):负责创建与管理享元角色
(5)客户端角色(client):本角色需要自行存储所有享元对象的外藴状态
2.实例
2.1单享元模式实例
饮料店中有一系列的冰淇淋用于外卖,冰淇淋有内藴状态,即冰淇淋的味道;冰淇淋没有环境因素,即没有外藴状态.如果开发一个管理系统为每一个冰淇淋都经理一个独立的对象,那么产生大量的对象.此时合理的处理方式是将冰淇淋按照种类(即味道)划分,每一种味道冰淇淋只创建一个对象并实行共享,所谓共享,主要是指冰淇淋味道的共享,制造方法的共享等.因此享元模式对饮料店而言,无须为每一份冰淇淋单独调制.当有需要时,店主可一次性地调制出足够当天使用的某风味冰淇淋.基于此运用享元模式设计如下
店主即客户端角色,冰淇淋享元工厂即享元工厂角色,冰淇淋享元接口即抽象享元角色,冰淇淋享元实现类及具体享元角色
2.2多享元模式实例
饮料店中的冰淇淋仅用于外卖,客户有意见提出希望在店中有相应的桌子用来消费冰淇淋,此时冰淇淋的桌子即为外藴状态。此时,单享元模式需要扩展为多享元模式、基于此运用多享元模式设计如下图
店主即客户端角色,冰淇淋享元工厂即享元工厂角色,冰淇淋享元接口即抽象享元角色,冰淇淋享元实现类即具体享元角色,复合享元即复合享元角色
应用场景
享元模式的优势在于:通过减少内存对象的数量,节省内存空间.基于此,我认为可以在以下几种情形下采用享元模式进行软件与实施.
1.软件系统对象过多时。
2.软件系统中的对象花费内存过多时
3.软件系统中对象状态,其绝大部分可外部化时
4.根据对象状态进行分类时,在去掉外部状态时,每个分类军可用一个对象取代
5.软件系统无须依靠对象的标志
3.实例源码:
3.1单享元模式
源码如下
3.2多享元模式
源码如下
Struts1 与享元模式
Struts1中的Action类体现了共享模式,例如我们在Action中声明了字段并设置了相关参数,如果初始值为88,当客户端有人访问将值设置为77,那么第二个使用者调用此字段时,得到结果将是88,而不是修改后的77.原因在于,Action声明字段属性对于体现请求均是共享的,当然此处的共享模式应用的是否合适,这个要结合项目需求,如果项目需求一个永不改变的数值,那么此模式在这里就比较合理,如果项目对字段进行了数值修改,我们也有方法解决.
比如,我们可以通过创建RquestProcessor的子类TestRequestProcessor,将Struts现有RequestProcessor类ProcessActionCreate()中的以下部分删除
instance = (Action)action.get(className);
if(instance != null){
if(log.usTraceEnbled()){
log.trace("Retuning existing Action instance");
}
return (instance);
}
剩下所有代码均放置与TestRequestProcessor的ProcessActionCrteate()中即可
所有"运用共享技术有效地支持大量细粒度的对象"我们可以理解为,当细粒度对象的数量过多时运行的代价相当高,此时运用共享技术可大大降低运行的代价
1.结构
1.1单纯享元模式结构
此模式,全部享元对象均可共享,如下图
(1)抽象享元角色(Flyweight):为具体享元角色规定了必须实现的方法,而外藴状态就是以参数的形式通过此方法传入,在java中科院由抽象类、接口类担当。
(2)具体享元角色(ConcreteFlyweight):实现抽象角色规定的方法.如果存在内藴状态,就扶着为内藴状态提供存储空间
(3)享元工厂角色(FlyweightFactory):负责创建和管理享元角色,要想达到共享的目的,这个角色的实现关键!(files可用HashMap或HashTable)
(4)客户端角色(client):维护对所有享元对象的引用,而且还需要存储对应的外藴状态。
1.2复合享元模式结构
此模式运用单纯享元,接口复合合成模式加以复用,如下图所示
(1)抽象享元角色(Flyweight):它是所有的具体享元类的超类
(2)具体享元角色(ConcreteFlyweight):实现抽象享元角色所规定的接口
(3)复合享元(UnsharableFlyweight):其代表的对象是不可共享的,但一个复合享元对象可愿意分解成为多个本身是单纯享元对象的组合。如上图中的ConcreteCompositeFlyweight、
(4)享元工厂角色(FlyweightFactory):负责创建与管理享元角色
(5)客户端角色(client):本角色需要自行存储所有享元对象的外藴状态
2.实例
2.1单享元模式实例
饮料店中有一系列的冰淇淋用于外卖,冰淇淋有内藴状态,即冰淇淋的味道;冰淇淋没有环境因素,即没有外藴状态.如果开发一个管理系统为每一个冰淇淋都经理一个独立的对象,那么产生大量的对象.此时合理的处理方式是将冰淇淋按照种类(即味道)划分,每一种味道冰淇淋只创建一个对象并实行共享,所谓共享,主要是指冰淇淋味道的共享,制造方法的共享等.因此享元模式对饮料店而言,无须为每一份冰淇淋单独调制.当有需要时,店主可一次性地调制出足够当天使用的某风味冰淇淋.基于此运用享元模式设计如下
店主即客户端角色,冰淇淋享元工厂即享元工厂角色,冰淇淋享元接口即抽象享元角色,冰淇淋享元实现类及具体享元角色
2.2多享元模式实例
饮料店中的冰淇淋仅用于外卖,客户有意见提出希望在店中有相应的桌子用来消费冰淇淋,此时冰淇淋的桌子即为外藴状态。此时,单享元模式需要扩展为多享元模式、基于此运用多享元模式设计如下图
店主即客户端角色,冰淇淋享元工厂即享元工厂角色,冰淇淋享元接口即抽象享元角色,冰淇淋享元实现类即具体享元角色,复合享元即复合享元角色
应用场景
享元模式的优势在于:通过减少内存对象的数量,节省内存空间.基于此,我认为可以在以下几种情形下采用享元模式进行软件与实施.
1.软件系统对象过多时。
2.软件系统中的对象花费内存过多时
3.软件系统中对象状态,其绝大部分可外部化时
4.根据对象状态进行分类时,在去掉外部状态时,每个分类军可用一个对象取代
5.软件系统无须依靠对象的标志
3.实例源码:
3.1单享元模式
源码如下
package model.flyweight1;
/*
* 抽象享元角色
*/
public interface Share {
public String work(String fettle);
}
package model.flyweight1;
/*
* 具体享元角色
* 属于conreteFlyweight角色
*/
public class ConcerteShare implements Share {
//内藴状态
private Character internalFettle = null;
@Override
public String work(String fettle) {
String a = "internalFettle="+internalFettle+",exterior Fettle="+fettle;
return a;
}
//将外藴状态传进去
public ConcerteShare(Character fettle) {
this.internalFettle = fettle;
}
}
package model.flyweight1;
import java.util.Hashtable;
/*
* 享元工厂角色类
* 属于FlyweightFactory
*/
public class ShareFactory {
private Hashtable matter = new Hashtable();
private Share share;
public ShareFactory(){
}
public Share factory(Character fettle){
if(matter.containsKey(fettle)){
return (Share) matter.get(fettle);
}else{
share = new ConcerteShare(fettle);
matter.put(fettle, share);
return share;
}
}
}
package model.flyweight1;
public class Client {
public static void main(String[] args) {
ShareFactory factory = new ShareFactory();
Share share =factory.factory(new Character('中'));
System.out.println("字体:"+share.work("黑体"));
System.out.println("字体:"+share.work("宋体"));
share =factory.factory(new Character('外'));
System.out.println("字体:"+share.work("仿体"));
}
}
3.2多享元模式
源码如下
package model.flyweight2;
/*
* 抽象享元角色
*/
public interface Share {
public String work(String fettle);
}
package model.flyweight2;
/*
* 具体享元角色
* 属于conreteFlyweight角色
*/
public class ConcerteShare implements Share {
//内藴状态
private Character internalFettle = null;
@Override
public String work(String fettle) {
String a = "internalFettle="+internalFettle+",exterior Fettle="+fettle;
return a;
}
//将外藴状态传进去
public ConcerteShare(Character fettle) {
this.internalFettle = fettle;
}
}
package model.flyweight2;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
/*
*复合享元角色
*即UnsharableFlyweight角色
*/
public class ConcreteCompositeShare implements Share {
private Hashtable matter = new Hashtable(10);
private Share share;
//传入外藴状态
@Override
public String work(String fettle) {
Share share = null;
for (Iterator it=matter.entrySet().iterator(); it.hasNext();) {
Map.Entry e = (Map.Entry)it.next();
share = (Share) e.getValue();
share.work(fettle);
}
return fettle;
}
public ConcreteCompositeShare(){
}
//添加一个新的单纯享元对象到聚合中
public void add(Character key,Share share){
matter.put(key, share);
}
}
package model.flyweight2;
import java.util.Hashtable;
/*
* 享元工厂角色类
* 属于FlyweightFactory
*/
public class ShareFactory {
private Hashtable matter = new Hashtable();
private Share share;
public ShareFactory(){
}
//单享元工厂方法,所需状态以参数形式传进去
public Share factory(Character fettle){
if(matter.containsKey(fettle)){
return (Share) matter.get(fettle);
}else{
share = new ConcerteShare(fettle);
matter.put(fettle, share);
return share;
}
}
//享元工厂方法,运用String参数传入状态
public Share factory(String compositeState){
ConcreteCompositeShare compositeShare = new ConcreteCompositeShare();
int length = compositeState.length();
Character fettle = null;
for (int i = 0; i < length; i++) {
fettle = new Character(compositeState.charAt(i));
System.out.println("factory("+fettle+")");
compositeShare.add(fettle, this.factory(fettle));
}
return compositeShare;
}
}
package model.flyweight2;
public class Client {
public static void main(String[] args) {
ShareFactory factory = new ShareFactory();
Share share = factory.factory("东南西");
System.out.println("内藴东南西,外藴均为字体:"+share.work("仿体"));
}
}
Struts1 与享元模式
Struts1中的Action类体现了共享模式,例如我们在Action中声明了字段并设置了相关参数,如果初始值为88,当客户端有人访问将值设置为77,那么第二个使用者调用此字段时,得到结果将是88,而不是修改后的77.原因在于,Action声明字段属性对于体现请求均是共享的,当然此处的共享模式应用的是否合适,这个要结合项目需求,如果项目需求一个永不改变的数值,那么此模式在这里就比较合理,如果项目对字段进行了数值修改,我们也有方法解决.
比如,我们可以通过创建RquestProcessor的子类TestRequestProcessor,将Struts现有RequestProcessor类ProcessActionCreate()中的以下部分删除
instance = (Action)action.get(className);
if(instance != null){
if(log.usTraceEnbled()){
log.trace("Retuning existing Action instance");
}
return (instance);
}
剩下所有代码均放置与TestRequestProcessor的ProcessActionCrteate()中即可