博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
结构模式--之--享元模式
阅读量:4678 次
发布时间:2019-06-09

本文共 6322 字,大约阅读时间需要 21 分钟。

享元模式是对象的结构模式,享元模式以共享的方式高效地支持大量的细粒度对象。享元对象能做到共享的关键区分内蕴状态和外蕴状态。
一个内蕴状态是存储在享元对象内部的,并且是不会随着环境改变而有所不同,因此,一个享元可以具有内蕴状态并可以共享。
一个外蕴状态是随着环境改变而改变,不可以共享的状态。享元对象 的外蕴状态必须由客户端保存,并在享元对象被创建之后,在需要使用的时候再传入到享元对象内部。外蕴状态不可以影响享元对象的内蕴状态。换句话说,它们是相互独立的。
 
根据所涉及的享元对象的内部表象,享元模式可以分成单纯享元模式和复合享元模式。
 
单纯享元模式:
在单纯享元模式中,所有的享元对象都是可以共享的。
 
单纯享元模式所涉及的角色如下:
1.抽象享元角色:此角色是所有的具体享元类的超类,为这些类规定出需要实现的公共接口。那些需要外蕴状态的操作可以通过调用商业方法以参数形式传入
2.具体享元角色:实现抽象享元角色所规定的接口。如果有内蕴状态的话,必须负责为内蕴状态提供存储空间。享元对象的内蕴状态必须与对象所处的周围环境无关,从而使得享元对象可以在系统内共享的。
3.享元工厂角色:本角色负责创建和管理享元角色。本角色必须保证享元对象可以被系统适当地共享。当一个客户端对象调用一个享元对象的时候,享元工厂角色会检查系统中是否已经有一个复合要求的享元对象。如果已经有了,享元工厂角色就应当提供这个已有的享元对象,如果系统中没有一个适当的享元对象的话,享元工厂角色就应当创建一个合适的享元对象。
4.客户端角色:本角色需要维护一个对所有享元对象的引用。本角色需要自行存储所有享元对象的外蕴状态。
 
示例性代码:
1 public class SimpleFlyweightTest { 2     public static void main(String[] args) { 3         //创建一个享元工厂对象 4         FlyweightFactory factory = new FlyweightFactory(); 5         //向享元工厂对象请求一个内蕴状态的为”a“的享元对象 6         Flyweight fly = factory.factory(new Character('a')); 7         //以参量方式传入一个外蕴状态 8         fly.operation("First Call"); 9         //向享元工厂对象请求一个内蕴状态的为”b“的享元对象10         fly = factory.factory(new Character('b'));11         //以参量方式传入一个外蕴状态12         fly.operation("Second Call");13         //向享元工厂对象请求一个内蕴状态的为”a“的享元对象14         fly = factory.factory(new Character('a'));15         //以参量方式传入一个外蕴状态16         fly.operation("Third Call");17     }18 19 }20 21 //抽象享元角色22 abstract class Flyweight{23     //示意性方法,参数state是外蕴状态24     abstract public void operation(String state);25 }26 27 //具体享元角色,享元角色可以有内蕴状态,这里以一个Character类型属性代表,它的值应当在享元对象被创建时28 //赋予,所有的内蕴状态在对象创建之后,就不会再改变了。29 class ConcreteFlyweight extends Flyweight{30     31     private Character intrinsicState = null;32     33     //构造子,内蕴状态作为参量传入34     public ConcreteFlyweight(Character state){35         this.intrinsicState = state;36     }37     //外蕴状态作为参量传入方法中,改变方法的行为,但并不改变对象的内蕴状态38     @Override39     public void operation(String state) {40         System.out.println("Intrinsic State="+intrinsicState + ", Extrinsic State =" + state );41     }42     43 }44 45 //享元工厂角色,客户端不可以直接将具体享元类实例化,必须通过一个工厂对象,利用一个factory()方法得到46 //享元对象。一般而言,享元工厂对象在整个系统中只有一个47 class FlyweightFactory{48     private HashMap map = new HashMap();49     private Flyweight lnkFlyweight;50     51     //默认构造子52     public FlyweightFactory(){}53     54     //构造子55     public Flyweight factory(Character state){56         if(map.containsKey(state)){57             return (Flyweight)map.get(state);58         }else{59             Flyweight fly = new ConcreteFlyweight(state);60             map.put(state, fly);61             return fly;62         }63         64     }65     66     //辅助方法67     public void checkFlyweight(){68         Flyweight fly;69         int i=0;70         System.out.println("-------check flyweight--------");71         for(Iterator it = map.entrySet().iterator();it.hasNext();){72             Map.Entry e = (Map.Entry)it.next();73             System.out.println("Item" +(++i)+":"+e.getKey());74         }75         System.out.println("----------check flyweight--------");76     }77 }

 

复合的享元模式:
单纯享元模式中,所有的享元对象都是单纯享元对象,也就是可以直接共享的。一种较复杂的情况是,将一些单纯享元使用合成模式加以复合,形成复合享元对象,这样的复合享元对象本身不能共享,但是它们可以分解成单纯享元对象,而后者可以共享。
 
角色:
1.抽象享元角色:它是所有的具体享元类的超类,为这些类规定需要实现的公共接口,那些需要外蕴状态的操作可以通过方法的参数传入。它使得享元变得可能,但并不强制子类实行共享,因此并非所有的享元对象都是可以共享的。
2.具体享元角色:实现抽象享元角色所规定的接口,如果有内蕴状态的话,必须负责为内蕴状态提供存储空间。享元对象的内蕴状态必须与对象所处的周围环境无关,从而使得享元对象可以在系统内共享。有时候具体享元角色又叫单纯具体享元角色,因为复合享元角色是由单纯具体享元角色通过复合而成的。
3.复合享元角色:复合享元角色所代表的对象是不可以共享的。但是一个复合享元对象可以分解成为多个本身是单纯享元对角的组合。复合享元角色又称为不可共享的享元对象
4.享元工厂:它负责创建和管理享元角色。本角色必须保证享元对象可以被系统适当地共享。
5.客户端角色:它还需要自行存储所有对象的外蕴状态。
示例代码:
1 public class MultiFlyweight {  2     public static void main(String[] args) {  3         //创建一个享元工厂对象  4         FlyweightFactory factory = new FlyweightFactory();  5         //向享元工厂对象请求一个内蕴状态的为”a“的享元对象  6         Flyweight fly = factory.factory(new Character('a'));  7         //以参量方式传入一个外蕴状态  8         fly.operation("First Call");  9         //向享元工厂对象请求一个内蕴状态的为”b“的享元对象 10         fly = factory.factory(new Character('b')); 11         //以参量方式传入一个外蕴状态 12         fly.operation("Second Call"); 13         //向享元工厂对象请求一个内蕴状态的为”a“的享元对象 14         fly = factory.factory(new Character('a')); 15         //以参量方式传入一个外蕴状态 16         fly.operation("Third Call"); 17          18         Flyweight fly2 = factory.factor("aba"); 19         fly2.operation("Composite Call"); 20          21     } 22  23 } 24 //抽象享元角色 25 abstract class Flyweight{ 26     abstract public void operation(String state); 27 } 28  29 //具体享元角色 30 class ConcreteFlyweight extends Flyweight{ 31      32     private Character intrinsicState = null; 33      34     //构造方法,内蕴状态作为参量传入 35     public ConcreteFlyweight(Character state){ 36         this.intrinsicState = state; 37     } 38     //外蕴状态作为参量传入到方法中 39     @Override 40     public void operation(String state) { 41         System.out.println("Intrinsic State="+intrinsicState + ", Extrinsic State =" + state ); 42     } 43      44 } 45  46 //具体复合享元角色 47 class ConcreteCompositeFlyweight extends Flyweight{ 48     private Map map = new HashMap(); 49     private Flyweight flyweight; 50     //增加一个新的单纯享元对象到聚焦中 51     public void add(Character key,Flyweight fly){ 52         map.put(key, fly); 53     } 54      55     //外蕴状态作为参量传入到方法中 56     @Override 57     public void operation(String extrinsicState) { 58         Flyweight fly = null; 59         for(Iterator it = map.entrySet().iterator();it.hasNext();){ 60             Map.Entry e = (Map.Entry)it.next(); 61             fly = (Flyweight)e.getValue(); 62             fly.operation(extrinsicState); 63         } 64     } 65      66 } 67  68 //享元工厂角色 69 class FlyweightFactory{ 70     private HashMap map = new HashMap(); 71     //复合享元工厂方法,所需状态以参量形式传入  72     public Flyweight factor(String compositeState){ 73         ConcreteCompositeFlyweight compositeFly = new ConcreteCompositeFlyweight(); 74         int length = compositeState.length(); 75         Character state = null; 76         for(int i=0;i

 

 
享元模式应当在什么条件下使用?
当以下所有条件都满足时,可以考虑使用享元模式
1.一个系统有大量的对象
2.这些对象的耗费大量的内存
3.这些对象的状态中的大部分都可以外部化
4.这些对象可以按照内蕴状态分成很多的组,当把外蕴对象从对象中剔除时,每一个组都可以仅用一个对象替代
5.软件系统不依赖于这些对象的身份,换言之,这些对象可以是不可分辨的。
最后,使用享元模式需要维护一个记录了系统已有的所有享元对象的表,而这需要耗费资源,因此,应当在有足够多的享元实例可供共享时才值得使用享元模式。
 
优缺点:
1.享元模式使得系统更加复杂,为了使对象可以共享,需要将一些状态外部化,这使得程序的逻辑复杂化
2.享元模式将享元对象的状态外部化,而读取外部状态使得运行时间稍微变长

转载于:https://www.cnblogs.com/wn398/p/3231995.html

你可能感兴趣的文章
C# .net 获取程序运行的路径的几种方法
查看>>
为什么需要Docker?
查看>>
国内5家云服务厂商 HTTPS 安全性测试横向对比
查看>>
how to control project
查看>>
转 python新手容易犯的6个错误
查看>>
第四节 -- 列表
查看>>
决策树
查看>>
团队作业
查看>>
如何避免在简单业务逻辑上面的细节上面出错
查看>>
大型网站高并发的架构演变图-摘自网络
查看>>
8丶运行及总结
查看>>
[洛谷P4234]最小差值生成树
查看>>
redis安装配置
查看>>
结对项目博客
查看>>
讨论记录:求大于一个时间段的最大平均积分,O(n)时间实现
查看>>
error) DENIED Redis is running in protected mode because protected mode is enabled报错
查看>>
CSS-16-margin值重叠问题
查看>>
selenium常用方法
查看>>
第二次作业
查看>>
ios 面试题
查看>>