标准 专业
多元 极客

设计模式实验室(7)——享元模式

什么是享元模式?

享元模式是一种对象结构型模式。

享元模式是将一系列细粒度的对象放入到容器中并对外共享。

在JVM中,每当我们实现一个字符串或者整形时,内存中都会一块空间与之对应,但是每次生产、销毁的代价是昂贵的,JVM通过实践不断地进行优化,最终出现了运行时常量池、IntegerCache等产物,这其实就是运用了享元模式。

常用的字符串(比如说java)和在默认情况下的-127~128都是最细粒度的对象,运行时常量池和缓存就是容器。

而在我们实际开发中,ThreadPool也是享元模式的具体实现。

核心结构

  • Flyweight。抽象享元,声明外部状态和内部状态的方法。
  • ConcreteFlyweight。具体享元,实现抽象享元声明的外部状态和内部状态的方法,每个具体享元提供了一个唯一的享元对象。
  • UnsharedConcreteFlyweight。非共享具体享元,享元对象可以共享也可以不共享,如果需要不共享的享元对象,可以使用非共享具体享元,当需要一个非共享享元对象时,可以直接实例化创建。
  • FlyweightFactory。享元工厂,用于创建并维护享元对象,它针对抽象享元进行编程,同时将具体享元维护在一个容器中,在实际中一般结合工厂模式进行享元工厂设计。

类图展示

享元模式

 

代码分析

代码展示部分,笔者偷懒举了一个简单享元模式,笔者将会详细分析Java线程池作为弥补。

六月苹果的WWDC开发者大会,苹果出乎意料的对硬件进行了升级,对于MacBook,其实13寸和15寸的模子几乎是一样的(TouchBar版),所以我们根据此例来实现享元模式。

首先声明抽象享元——MacBook类:

/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/1/20 0020.
 * 享元模式——抽象享元
 */
public abstract class Macbook {

    protected String size;  

    public Macbook(String size) {
        this.size = size;
    }

    public void produceMacbook(String color) {
        System.out.println("produce macbook which size is ".concat(this.size).concat(" and size is ".concat(color)));
    }
}

继续,我们创造两个具体享元。

13寸的MacBook:

/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/1/20 0020.
 * 享元模式——具体享元
 */
public class ThirteenSizeMacbook extends Macbook {

    public ThirteenSizeMacbook(String size) {
        super(size);
    }
}

15寸的MacBook:

/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/1/20 0020.
 * 享元模式——具体享元
 */
public class FifteenSizeMacbook extends Macbook {

   public FifteenSizeMacbook(String size) {
      super(size);
   }
}

有了享元对象,我们还需要一个容器来装载它们:

/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/1/20 0020.
 * 享元模式——工厂
 */
public class MacbookFactory {

   private static MacbookFactory macbook = new MacbookFactory();

   private static Map<String, Macbook> macbookMap;

   private MacbookFactory() {
      macbookMap = new HashMap<String, Macbook>();
      Macbook fifteenSizeMacbook = new FifteenSizeMacbook("15");
      Macbook thirteenSizeMacbook = new ThirteenSizeMacbook("13");
      macbookMap.put("13", thirteenSizeMacbook);
      macbookMap.put("15", fifteenSizeMacbook);
   }

   public static MacbookFactory getInstance() {
      return macbook;
   }

   public static Macbook getMacbook(String size) {
      return macbookMap.get(size);
   }
}

惯例,测试代码:

/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/1/20 0020.
 * 享元模式测试
 */
public class FlyWeightTest {

    public static void main(String[] args) {
        flyWeightTest();
    }

    private static void flyWeightTest() {
        try {
            MacbookFactory factory = MacbookFactory.getInstance();
            // 获取两个13寸的macbook
            Macbook thirteenSizeMacbookOne = MacbookFactory.getMacbook("13");
            Macbook thirteenSizeMacbookTwo = MacbookFactory.getMacbook("13");
            // 获取两个15寸的macbook
            Macbook fifteenSizeMacbookOne = MacbookFactory.getMacbook("15");
            Macbook fifteenSizeMacbookTwo = MacbookFactory.getMacbook("15");
            // 两两比较对象
            System.out.println(thirteenSizeMacbookOne == thirteenSizeMacbookTwo);
            System.out.println(fifteenSizeMacbookOne == fifteenSizeMacbookTwo);
            // 生产
            thirteenSizeMacbookOne.produceMacbook("grey");
            thirteenSizeMacbookTwo.produceMacbook("silver");
            fifteenSizeMacbookOne.produceMacbook("grey");
            fifteenSizeMacbookTwo.produceMacbook("silver");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

模式总结

优点

  • 享元模式下,原子对象的外部状态相对独立,并且不会影响其内部状态,从而使得享元对象可以被共享。
  • 极大的减少了内存中细粒度对象的数量,节省内存资源,提高了系统性能。

缺点

  • 享元模式需要分离出原子对象的外部状态和内部状态,提高了系统设计的复杂度。
  • 面向窄化,享元池或者享元对象设计不当,很可能造成系统资源的极大浪费。

适用场景

  • 系统中含有大量相同或相似的细粒度对象。
  • 对象的状态可以对外展示。
  • 当创建或者销毁某些相同或相似对象的代价较高时,可以通过预先创建一个享元池,比如说,线程池。
赞(2) 投币

评论 抢沙发

慕勋的实验室慕勋的研究院

码字不容易,路过请投币

支付宝扫一扫

微信扫一扫