深入探索Java设计模式之享元模式

抽丝剥茧 细说架构那些事——【优锐课】

享元模式适用于需要大量相同类型对象的情况。在此,设计布局可以减少创建多个对象的方式。对象在运行时会消耗资源,因此最好在内存中使用较少的对象。它减少了内存占用并利用了程序的整体性能。优锐课这篇文章通过Java中的一个简单示例深入研究了这种模式。

总览

轻量级模式减少了重复数据的使用。通常的做法是将对象设计成细粒度以利用其使用的灵活性。但是,问题是对象在运行时会消耗资源。粒度会不利地影响应用程序的性能,因为需要将运行时对象容纳在更大的内存集中。每个对象不仅消耗内存,而且消耗CPU周期。在这种情况下,轻量化模式可以通过减少细粒度对象的重复实例化来解决。

享元模式Flyweight Pattern

享元模式分为两部分:
• 内部的:这是独立的部分,数据存储在对象中,与享元模式上下文无关。结果,它对于所有相同的固有数据都是可共享的,因此可以用享元模式对象替换。
• 外在的: 这是从属部分,其中保留了举重对象的上下文信息。这是不可共享的。状态由客户端对象存储,并根据要求传递给享元模式对象。

享元模式的使用

在我们有许多表示相同值的对象的情况下,这很有用。因此,它使不可变对象的值可共享。例如,在下面的代码片段中观察Java标准库的Integer包装器类的valueOf()方法如何检查给定参数的值。

public static Integer valueOf(int i) {
   if (i >= IntegerCache.low && i <= IntegerCache.high)
      return IntegerCache.cache[i + (-IntegerCache.low)];
   return new Integer(i);
}

如果该值先前已缓存,则该方法将返回构造函数实例,而不是创建一个新对象。因为缓存是在静态块中初始化的,所以仅在第一次调用时才创建Integer实例。请注意,IntegerCache类是在Integerclass中定义的私有静态类。

private static class IntegerCache {
   // ...
   static {
      // ...
      cache = new Integer[(high - low) + 1];
      int j = low;
      for (int k = 0; k < cache.length; k++)
         cache[k] = new Integer(j++);
      // Range [-128, 127] must be interned (JLS7 5.1.7)
      assert IntegerCache.high >= 127;
   }
   // ...
}

现在,我们可以测试Integer类是否创建两个不同的对象(如果值相同)。将图1中的输出与以下代码进行比较。

public class JustForTesting {
   public static void main(String[] args){
      final Integer intObj1 = Integer.valueOf(10);
      final Integer intObj2 = Integer.valueOf(10);
      System.out.println("First Case");
      if (intObj1 == intObj2){
         System.out.println("If the values are same " +
            "then the objects are also same.");
      } else {
         System.out.println("If the values are different " +
            "then the objects are also distinct.");
      }
      // Now, if we change the same value to a different
      // value, it becomes two distinct objects

      final Integer intObj3 = Integer.valueOf(10);
      final Integer intObj4 = Integer.valueOf(20);
      System.out.println("Second Case");
      if (intObj3 == intObj4){
         System.out.println("If the values are same " +
            "then the objects are also same.");
      } else {
         System.out.println("If the values are different " +
            "then the objects are also distinct.");
      }
   }
}

输出

在这里插入图片描述
图1:前面代码的输出

实现享元模式

这是享元模式的简单实现。观察如何限制具有相同值的对象创建新对象,而不是提供池中已经存在的对象的副本。工厂中的对象池充当保留享元模式实例的缓存。

package testpattern;
public class Car {
   private String color;
   public Car(String color){
      this.color = color;
      System.out.println("Painted with "+color+" color.");
   }
   public String getColor() {
      return color;
   }
}
package testpattern;
import java.util.ArrayList;
import java.util.List;
public class CarFactory {
   private List<Car> carpool = new ArrayList<>();
   public Car getFlyweightCar(String color) {
      for (Car c: carpool) {
         if (c.getColor().equals(color)){
            System.out.println(color +
               " car is already in the pool!");
            return c;
         }
      }
      Car car = new Car(color);
      carpool.add(car);
      return car;
   }
}
package testpattern;
public class App {
   public static void main(String[] args) {
      CarFactory cf = new CarFactory();
      cf.getFlyweightCar("RED");
      cf.getFlyweightCar("BLUE");
      cf.getFlyweightCar("GREEN");
      cf.getFlyweightCar("PURPLE");
      cf.getFlyweightCar("RED");
      cf.getFlyweightCar("BLUE");
      cf.getFlyweightCar("BLACK");
   }
}

输出

在这里插入图片描述
图2:享元模式实现的输出

结论

享元模式是在许多情况下使用的常见模式,有时程序员会在不知不觉中使用它。这种模式说明了我们如何使用许多内存不足的对象。如前所述,我们必须始终尽可能利用不变的Integer类的valueOf方法,因为当我们调用new时,即使缓存包含相同的对象,也会创建一个新实例。正如我们已经讨论过的那样,valueOf方法还可以工作。这是使用享元模式的优势。
在这里插入图片描述
ps:加入Java学习资料交流qq群:907135806和我们一起探讨吧!有想要JVM、Mysql、Tomcat、Spring Boot、Spring Cloud、Zookeeper、Kafka、RabbitMQ、RockerMQ、Redis、ELK、Git等Java学习资料、视频课程和学习路线的童鞋也可以加vx:ddmsiqi 领取啦,共同进步~

发布了32 篇原创文章 · 获赞 0 · 访问量 420
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 游动-白 设计师: 上身试试

分享到微信朋友圈

×

扫一扫,手机浏览