设计模式(28)-----结构型模式-----享元模式

Posted qingruihappy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式(28)-----结构型模式-----享元模式相关的知识,希望对你有一定的参考价值。

享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。

享元模式尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象。我们将通过创建 5 个对象来画出 20 个分布于不同位置的圆来演示这种模式。由于只有 5 种可用的颜色,所以 color 属性被用来检查现有的 Circle 对象。这里只有5个对象的。

 

 

介绍

意图:运用共享技术有效地支持大量细粒度的对象。

主要解决:在有大量对象时,有可能会造成内存溢出,我们把其中共同的部分抽象出来,如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建。

何时使用: 1、系统中有大量对象。 2、这些对象消耗大量内存。 3、这些对象的状态大部分可以外部化。 4、这些对象可以按照内蕴状态分为很多组,当把外蕴对象从对象中剔除出来时,每一组对象都可以用一个对象来代替。 5、系统不依赖于这些对象身份,这些对象是不可分辨的。

如何解决:用唯一标识码判断,如果在内存中有,则返回这个唯一标识码所标识的对象。

关键代码:用 HashMap 存储这些对象。

应用实例: 1、JAVA 中的 String,如果有则返回,如果没有则创建一个字符串保存在字符串缓存池里面。 2、数据库的数据池。

优点:大大减少对象的创建,降低系统的内存,使效率提高。

缺点:提高了系统的复杂度,需要分离出外部状态和内部状态,而且外部状态具有固有化的性质,不应该随着内部状态的变化而变化,否则会造成系统的混乱。

使用场景: 1、系统有大量相似对象。 2、需要缓冲池的场景。

注意事项: 1、注意划分外部状态和内部状态,否则可能会引起线程安全问题。 2、这些类必须有一个工厂对象加以控制。 

 

 

我们将创建一个 Shape 接口和实现了 Shape 接口的实体类 Circle。下一步是定义工厂类 ShapeFactory

ShapeFactory 有一个 CircleHashMap,其中键名为 Circle 对象的颜色。无论何时接收到请求,都会创建一个特定颜色的圆。ShapeFactory 检查它的 HashMap 中的 circle 对象,如果找到 Circle 对象,则返回该对象,否则将创建一个存储在 hashmap 中以备后续使用的新对象,并把该对象返回到客户端。

FlyWeightPatternDemo,我们的演示类使用 ShapeFactory 来获取 Shape 对象。它将向 ShapeFactory 传递信息(red / green / blue/ black / white),以便获取它所需对象的颜色。

 

 

技术分享图片

 

 

步骤 1

创建一个接口。

package com.DesignPatterns.Flyweight;

public interface Shape {
    void draw();
}

步骤 2

创建实现接口的实体类。

package com.DesignPatterns.Flyweight;

public class Circle implements Shape {
    private String color;
    private int x;
    private int y;
    private int radius;
  
    public Circle(String color){
       this.color = color;     
    }
  
    public void setX(int x) {
       this.x = x;
    }
  
    public void setY(int y) {
       this.y = y;
    }
  
    public void setRadius(int radius) {
       this.radius = radius;
    }
  
    @Override
    public void draw() {
       System.out.println("Circle: Draw() [Color : " + color 
          +", x : " + x +", y :" + y +", radius :" + radius);
    }
 }

 

 

 

步骤 3

创建一个工厂,生成基于给定信息的实体类的对象。

 

package com.DesignPatterns.Flyweight;

import java.util.HashMap;
/**
 * 该模式说白了就是对某一个特定的属性值创建一个对象,防止创建的对象太多。
 * 例如本例子中,虽然便利了20次,但是以颜色为基准的话,每次同一个颜色只能创建一个对象的。
 * @date 2018年11月7日
 * @version 10.28版本
 * @说明:
 */
public class ShapeFactory {
   private static final HashMap<String, Shape> circleMap = new HashMap<>();
 
   public static Shape getCircle(String color) {
      Circle circle = (Circle)circleMap.get(color);
 
      if(circle == null) {
         circle = new Circle(color);
         circleMap.put(color, circle);
         System.out.println("Creating circle of color : " + color);
      }
      return circle;
   }
   
   public static int getSum(){
       return circleMap.size();
   }
}

步骤 4

使用该工厂,通过传递颜色信息来获取实体类的对象。

 

package com.DesignPatterns.Flyweight;

public class FlyweightPatternDemo {
    private static final String colors[] = 
       { "Red", "Green", "Blue", "White", "Black" };
    public static void main(String[] args) {
  
       for(int i=0; i < 20; ++i) {
          Circle circle = 
             (Circle)ShapeFactory.getCircle(getRandomColor());
          circle.setX(getRandomX());
          circle.setY(getRandomY());
          circle.setRadius(100);
          circle.draw();
          System.out.println("共享池中总共有"+ShapeFactory.getSum()+"中颜色的圆形");
       }
       System.out.println("======最后一共绘制了"+ShapeFactory.getSum()+"中颜色的圆形======");

    }
    private static String getRandomColor() {
       return colors[(int)(Math.random()*colors.length)];
    }
    private static int getRandomX() {
       return (int)(Math.random()*100 );
    }
    private static int getRandomY() {
       return (int)(Math.random()*100);
    }
    

 }

 

 

Creating circle of color : Green
Circle: Draw() [Color : Green, x : 4, y :88, radius :100
共享池中总共有1中颜色的圆形
Creating circle of color : Red
Circle: Draw() [Color : Red, x : 34, y :46, radius :100
共享池中总共有2中颜色的圆形
Creating circle of color : Blue
Circle: Draw() [Color : Blue, x : 85, y :53, radius :100
共享池中总共有3中颜色的圆形
Creating circle of color : White
Circle: Draw() [Color : White, x : 69, y :13, radius :100
共享池中总共有4中颜色的圆形
Circle: Draw() [Color : Red, x : 4, y :67, radius :100
共享池中总共有4中颜色的圆形
Circle: Draw() [Color : Green, x : 39, y :64, radius :100
共享池中总共有4中颜色的圆形
Circle: Draw() [Color : Green, x : 10, y :34, radius :100
共享池中总共有4中颜色的圆形
Circle: Draw() [Color : White, x : 0, y :14, radius :100
共享池中总共有4中颜色的圆形
Circle: Draw() [Color : Red, x : 38, y :4, radius :100
共享池中总共有4中颜色的圆形
Circle: Draw() [Color : White, x : 71, y :1, radius :100
共享池中总共有4中颜色的圆形
Circle: Draw() [Color : Red, x : 46, y :87, radius :100
共享池中总共有4中颜色的圆形
Circle: Draw() [Color : Blue, x : 83, y :46, radius :100
共享池中总共有4中颜色的圆形
Circle: Draw() [Color : Green, x : 87, y :81, radius :100
共享池中总共有4中颜色的圆形
Circle: Draw() [Color : Blue, x : 28, y :48, radius :100
共享池中总共有4中颜色的圆形
Circle: Draw() [Color : White, x : 6, y :98, radius :100
共享池中总共有4中颜色的圆形
Circle: Draw() [Color : White, x : 31, y :16, radius :100
共享池中总共有4中颜色的圆形
Circle: Draw() [Color : Blue, x : 27, y :45, radius :100
共享池中总共有4中颜色的圆形
Circle: Draw() [Color : Green, x : 37, y :60, radius :100
共享池中总共有4中颜色的圆形
Creating circle of color : Black
Circle: Draw() [Color : Black, x : 32, y :70, radius :100
共享池中总共有5中颜色的圆形
Circle: Draw() [Color : Blue, x : 77, y :65, radius :100
共享池中总共有5中颜色的圆形
======最后一共绘制了5中颜色的圆形======

 

 

 

 

其实在Java中就存在这种类型的实例:String。

  Java中将String类定义为final(不可改变的),JVM中字符串一般保存在字符串常量池中,这个字符串常量池在jdk 6.0以前是位于常量池中,位于永久代,而在JDK 7.0中,JVM将其从永久代拿出来放置于堆中。

  我们使用如下代码定义的两个字符串指向的其实是同一个字符串常量池中的字符串值。

 

1 String s1 = "abc";

2 String s2 = "abc";

 如果我们以s1==s2进行比较的话所得结果为:true,因为s1和s2保存的是字符串常量池中的同一个字符串地址。这就类似于我们今天所讲述的享元模式,字符串一旦定义之后就可以被共享使用,因为他们是不可改变的,同时被多处调用也不会存在任何隐患。

  享元模式使用的场景:

    当我们项目中创建很多对象,而且这些对象存在许多相同模块,这时,我们可以将这些相同的模块提取出来采用享元模式生成单一对象,再使用这个对象与之前的诸多对象进行配合使用,这样无疑会节省很多空间。

 

以上是关于设计模式(28)-----结构型模式-----享元模式的主要内容,如果未能解决你的问题,请参考以下文章

结构型模式 享元模式

15结构型模式之享元模式

重学Java设计模式-结构型模式-享元模式

设计模式 结构型模式 -- 享元模式(定义 示例 优缺点分析 使用场景)

Python 设计模式 — 结构型模式 — 享元模式

Python 设计模式 — 结构型模式 — 享元模式