Java设计模式之享元模式
2018-01-18 21:34
363 查看
亨元模式(Flyweight Pattern): 如想让某个类的一个实例能用来提供许多”虚拟实例”, 就使用蝇量模式。
享元模式的详解
享元模式采用一个共享来避免大量拥有相同内容对象的开销。这种开销最常见、最直观的就是内存的消耗。享元对象能做到共享的关键是区分内蕴状态和外蕴状态。
内蕴状态:是指存储在享元对象内部的,并且是不会随着环境的改变而改变的。所以享元对象可以具有内蕴状态,并可以被共享。
外蕴状态:是随环境的改变而改变的,不可以共享的。享元对象的外蕴状态必须由客户端保存,并在享元对象呗创建之后,在需要使用的时候在传入到享元对象内部。外蕴状态不可以影响享元对象的内蕴状态,他们是互相独立的。
享元模式有可以分为:单纯享元模式和符合享元模式
角色说明:
抽象享元角色(Flyweight):给出一个抽象接口,以规定出所有具体享元角色需要实现的方法。
具体享元角色(ConcreteFlyweight):实现抽象享元角色所规定的出的接口。如果有内蕴状态的话,必须负责为内蕴状态提供存储空间。
享元工厂角色(FlyweightFactory):本角色负责创建和管理享元角色。享元工程必须保证享元对象可以被系统适当地共享。当一个客户端对象调用一个享元对象的时候,享元工程角色会检查系统中是否已经有一个符合要求的享元对象。如果已经有了,享元工厂就应当提供这个已有的享元对象;如果系统中没有一个适当的享元对象的话,享元工厂就应当创建一个合适的享元对象。
代码演示,抽象享元类:
具体享元类:
享元工厂类:
客户端测试类:
运行结果:
类图:
角色说明:
复合享元角色(CompositeFlyweight):复合享元角色所代表第的对象是不可以共享的,但是一个复合享元对象可以分解成为多个单纯享元对象的组合。复合享元角色是不可共享的享元对象。
剩余的角色和单纯享元对象角色说明一样。
代码演示,抽象享元类:
具体享元类:
复合享元类:
复合享元对象是由单纯享元对象通过复合而成的,所以有add()这个复合方法。由于复合对象是由不同的子元素,而这些子元素是在复合享元对象创建之后才加入的。这就意味着复合享元对象的内蕴状态是随时会改变的,所以它不能共享。
享元工厂类:
客户端测试类:
运行结果:
享元模式的优点:
享元模式可以很好的降低内存中对象的数量,从而有效的减少内存的消耗。
缺点:
同时享元模式也会使得系统更加复杂,为了使对象可以共享,需要将一些状态外部化,这使得程序的逻辑复杂化。
享元模式将享元对象的状态外部化,而读取外部状态使得云心时间稍微变长。
享元模式的适用场景:
一个系统中存在着大量细粒度的对象;
大量细粒度的对象耗费了大量的内存;
大量细粒度的对象状态中的大部分都可以外部化;
大量细粒度的对象可以按照内蕴状态分成很多组,当把外蕴对象从对象中剔除时,每一个组都可以仅用一个对象代替;
系统不依赖于这些对象的身份,换而言之,这些对象允许不用分辨。
题外话:其实Java中的String类型就使用了享元模式。下面看个简单的例子
这说明了str和str1两个对象引用的是常量池中的同一个字符串常量”Layne”。
享元模式的详解
享元模式采用一个共享来避免大量拥有相同内容对象的开销。这种开销最常见、最直观的就是内存的消耗。享元对象能做到共享的关键是区分内蕴状态和外蕴状态。
内蕴状态:是指存储在享元对象内部的,并且是不会随着环境的改变而改变的。所以享元对象可以具有内蕴状态,并可以被共享。
外蕴状态:是随环境的改变而改变的,不可以共享的。享元对象的外蕴状态必须由客户端保存,并在享元对象呗创建之后,在需要使用的时候在传入到享元对象内部。外蕴状态不可以影响享元对象的内蕴状态,他们是互相独立的。
享元模式有可以分为:单纯享元模式和符合享元模式
单纯享元模式
类图:角色说明:
抽象享元角色(Flyweight):给出一个抽象接口,以规定出所有具体享元角色需要实现的方法。
具体享元角色(ConcreteFlyweight):实现抽象享元角色所规定的出的接口。如果有内蕴状态的话,必须负责为内蕴状态提供存储空间。
享元工厂角色(FlyweightFactory):本角色负责创建和管理享元角色。享元工程必须保证享元对象可以被系统适当地共享。当一个客户端对象调用一个享元对象的时候,享元工程角色会检查系统中是否已经有一个符合要求的享元对象。如果已经有了,享元工厂就应当提供这个已有的享元对象;如果系统中没有一个适当的享元对象的话,享元工厂就应当创建一个合适的享元对象。
代码演示,抽象享元类:
public interface Flyweight { // 示例操作方法,参数state是外蕴状态 public void operation(String state); }
具体享元类:
public class ConcreteFlyweight implements Flyweight { private String intrinsicState = null; // 内蕴状态在构造时作为参数传入,传入之后是不可改变的 public ConcreteFlyweight(String state) { this.intrinsicState = state; } // 外蕴状态作为参数传入方法中,改变方法的行为, 但是并不改变对象的内蕴状态。 @Override public void operation(String state) { System.out.println("内蕴状态: " + this.intrinsicState); System.out.println("外蕴状态: " + state); } }
享元工厂类:
public class FlyweightFactory { //对象的内蕴状态是不变的,可以作为该对象的标识 private Map<String, Flyweight> resource = new HashMap<String, Flyweight>(); public Flyweight factory(String state) { // 先从缓存中查找对象,查看是否有适合的对象进行分享 Flyweight fly = resource.get(state); if (fly == null) { // 如果没有就应当创建一个合适的Flyweight对象 fly = new ConcreteFlyweight(state); // 把这个新创建的Flyweight对象添加到缓存中 resource.put(state, fly); System.out.println(state + "状态对应对象不存在,已经新建一个新的对象"); } else { System.out.println(state + "状态对应对象已经存在,已从缓存中取出"); } return fly; } }
客户端测试类:
public class Test { public static void main(String[] args) { FlyweightFactory factory = new FlyweightFactory(); Flyweight fly = factory.factory("NBA"); fly.operation("Request one"); System.out.println("============="); fly = factory.factory("CBA"); fly.operation("Request two"); System.out.println("============="); fly = factory.factory("NBA"); fly.operation("Request three"); } }
运行结果:
复合享元模式
在单纯享元模式中,所有的享元对象都是单纯享元对象,都可以直接进行共享。还有另一种较为复杂的情况,将一些单纯享元对象复合起来,形成复合享元对象。这种复合享元对象本身是不能共享的,但是可以分解成单纯享元对象,然后进行单纯享元对象的分享。类图:
角色说明:
复合享元角色(CompositeFlyweight):复合享元角色所代表第的对象是不可以共享的,但是一个复合享元对象可以分解成为多个单纯享元对象的组合。复合享元角色是不可共享的享元对象。
剩余的角色和单纯享元对象角色说明一样。
代码演示,抽象享元类:
public interface Flyweight { // 示例操作方法,参数state是外蕴状态 public void operation(String state); }
具体享元类:
public class ConcreteFlyweight implements Flyweight { private String intrinsicState = null; // 内蕴状态在构造时作为参数传入,传入之后是不可改变的 public ConcreteFlyweight(String state) { this.intrinsicState = state; } // 外蕴状态作为参数传入方法中,改变方法的行为, 但是并不改变对象的内蕴状态。 @Override public void operation(String state) { System.out.println("内蕴状态: " + this.intrinsicState); System.out.println("外蕴状态: " + state); } }
复合享元类:
public class CompositeFlyweight implements Flyweight { private Map<String, Flyweight> compositeResource = new HashMap<String, Flyweight>(); // 复合一个新的单纯享元对象 public void add(String key, Flyweight fly) { compositeResource.put(key, fly); } // 外蕴状态作为参数传入到方法中 @Override public void operation(String state) { Flyweight fly = null; for (Object object : compositeResource.keySet()) { fly = compositeResource.get(object); fly.operation(state); } } }
复合享元对象是由单纯享元对象通过复合而成的,所以有add()这个复合方法。由于复合对象是由不同的子元素,而这些子元素是在复合享元对象创建之后才加入的。这就意味着复合享元对象的内蕴状态是随时会改变的,所以它不能共享。
享元工厂类:
public class FlyweightFactory { //对象的内蕴状态是不变的,可以作为该对象的标识 private Map<String, Flyweight> resource = new HashMap<String, Flyweight>(); //复合享元的工厂方法 public Flyweight factory(List<String> compositeState) { CompositeFlyweight compositeFlyweight = new CompositeFlyweight(); for (String state : compositeState) { compositeFlyweight.add(state, this.factory(state)); } return compositeFlyweight; } public Flyweight factory(String state) { // 先从缓存中查找对象,查看是否有适合的对象进行分享 Flyweight fly = resource.get(state); if (fly == null) { // 如果没有就应当创建一个合适的Flyweight对象 fly = new ConcreteFlyweight(state); // 把这个新创建的Flyweight对象添加到缓存中 resource.put(state, fly); System.out.println(state + "状态对应对象不存在,已经新建一个新的对象"); } else { System.out.println(state + "状态对应对象已经存在,已从缓存中取出"); } return fly; } }
客户端测试类:
public class Test { public static void main(String[] args) { List<String > compositeState = new ArrayList<String>(); compositeState.add("NBA"); compositeState.add("CBA"); compositeState.add("NBA"); FlyweightFactory flyFactory = new FlyweightFactory(); Flyweight compositeFly1 = flyFactory.factory(compositeState); System.out.println("================"); Flyweight compositeFly2 = flyFactory.factory(compositeState); compositeFly1.operation("Request"); System.out.println("================"); System.out.println("复合享元角色是否可以共享:" + (compositeFly1 == compositeFly2)); System.out.println("================"); String state = "CBA"; Flyweight fly1 = flyFactory.factory(state); Flyweight fly2 = flyFactory.factory(state); System.out.println("单纯享元角色是否可以共享:" + (fly1 == fly2)); } }
运行结果:
享元模式的优点:
享元模式可以很好的降低内存中对象的数量,从而有效的减少内存的消耗。
缺点:
同时享元模式也会使得系统更加复杂,为了使对象可以共享,需要将一些状态外部化,这使得程序的逻辑复杂化。
享元模式将享元对象的状态外部化,而读取外部状态使得云心时间稍微变长。
享元模式的适用场景:
一个系统中存在着大量细粒度的对象;
大量细粒度的对象耗费了大量的内存;
大量细粒度的对象状态中的大部分都可以外部化;
大量细粒度的对象可以按照内蕴状态分成很多组,当把外蕴对象从对象中剔除时,每一个组都可以仅用一个对象代替;
系统不依赖于这些对象的身份,换而言之,这些对象允许不用分辨。
题外话:其实Java中的String类型就使用了享元模式。下面看个简单的例子
这说明了str和str1两个对象引用的是常量池中的同一个字符串常量”Layne”。
相关文章推荐
- 详解java设计模式(七)之享元模式(结构型)
- Java程序性能优化 读书笔记(四)设计模式:享元模式
- JAVA设计模式之享元模式
- java设计模式---享元模式
- java设计模式之享元模式
- 【Java设计模式】· 享元模式 (Flyweight Pattern)
- Java设计模式笔记之享元模式
- (转)Java设计模式之享元模式
- java 设计模式之享元模式
- Java设计模式之——享元模式
- java设计模式(十一)--享元模式
- JAVA 设计模式 享元模式
- java设计模式---享元模式
- Java设计模式之享元模式
- Java设计模式—享元模式
- 浅谈Java设计模式(十二)享元模式(Flyweight)
- Java设计模式之《享元模式》及应用场景
- java设计模式13_享元模式
- JAVA设计模式——享元模式
- 【转】Java设计模式之《享元模式》及应用场景