享元模式--Flyweight

Posted ssh-html

tags:

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

享元模式具体是怎么回事呢,我也不是很清楚啊,只是在看视频的过程中学到的,只其中涉及到的是Java中的基本数据类型的封装类,在进行拆箱以及封箱的时候所用到的一种涉及模式

一。概述

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

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

二、介绍

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

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

何时使用:

1、系统中有大量对象。

2、这些对象消耗大量内存。

3、这些对象的状态大部分可以外部化。

4、这些对象可以按照内蕴状态分为很多组,当把外蕴对象从对象中剔除出来时,每一组对象都可以用一个对象来代替。

5、系统不依赖于这些对象身份,这些对象是不可分辨的。

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

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

应用实例: 

1、JAVA 中的 String,如果有则返回,如果没有则创建一个字符串保存在字符串缓存池里面。

2、数据库的数据池。

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

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

使用场景: 

1、系统有大量相似对象。

2、需要缓冲池的场景。

注意事项: 

1、注意划分外部状态和内部状态,否则可能会引起线程安全问题。

2、这些类必须有一个工厂对象加以控制。

三、实现

1、创建一个接口

1 public interface Shape {
2    void draw();
3 }

2、创建实现接口的实现类

 1 public class Circle implements Shape {
 2    private String color;
 3    private int x;
 4    private int y;
 5    private int radius;
 6  
 7    public Circle(String color){
 8       this.color = color;     
 9    }
10  
11    public void setX(int x) {
12       this.x = x;
13    }
14  
15    public void setY(int y) {
16       this.y = y;
17    }
18  
19    public void setRadius(int radius) {
20       this.radius = radius;
21    }
22  
23    @Override
24    public void draw() {
25       System.out.println("Circle: Draw() [Color : " + color 
26          +", x : " + x +", y :" + y +", radius :" + radius);
27    }
28 }

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

 1 import java.util.HashMap;
 2  
 3 public class ShapeFactory {
 4    private static final HashMap<String, Shape> circleMap = new HashMap<>();
 5  
 6    public static Shape getCircle(String color) {
 7       Circle circle = (Circle)circleMap.get(color);
 8  
 9       if(circle == null) {
10          circle = new Circle(color);
11          circleMap.put(color, circle);
12          System.out.println("Creating circle of color : " + color);
13       }
14       return circle;
15    }
16 }

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

 1 public class FlyweightPatternDemo {
 2    private static final String colors[] = 
 3       { "Red", "Green", "Blue", "White", "Black" };
 4    public static void main(String[] args) {
 5  
 6       for(int i=0; i < 20; ++i) {
 7          Circle circle = 
 8             (Circle)ShapeFactory.getCircle(getRandomColor());
 9          circle.setX(getRandomX());
10          circle.setY(getRandomY());
11          circle.setRadius(100);
12          circle.draw();
13       }
14    }
15    private static String getRandomColor() {
16       return colors[(int)(Math.random()*colors.length)];
17    }
18    private static int getRandomX() {
19       return (int)(Math.random()*100 );
20    }
21    private static int getRandomY() {
22       return (int)(Math.random()*100);
23    }
24 }

上述讲述是在菜鸟教程上面的官方讲解:http://www.runoob.com/design-pattern/flyweight-pattern.html

总结:

听到这个设计模式是在《张孝详J2SE高深讲解》中,张老师是在讲解基本数据类型的封装类型的时候提及到了这个设计模式,当时举例说明了一下,为什么下面的代码返回结果不同

Integer num1 = 12;
Integer num2 = 12;
//该结果为true
System.out.println(num1 == num2);

Integer num3 = 129;
Integer num4 = 129;
//该结果为false
System.out.println(num3 == num4);

其实,在封箱与装箱 的过程中,就Integer对象而言,当数字在 -128-127之前的时候,每当碰到这样的数字,就会将它的值缓存起来,存到一个池中,当下次再创建对象的时候,只要池中存在的话,就直接引用了,就不用创建对象了,这样做的话,会节省很多内存空间,这其中就用了设计模式中的享元模式

其实,细节真的很重要,我不知道自己为什么重新看一遍基础的东西,当然很大一部分原因是为了应付面试,但是,你可以发现,你真的能从中学习到很多知识,这也许就是我们为什么不管哪一个行业,都应该不断的去学习,不仅使得自己牛逼 ,还能从中学习到很多生活中道理,细节决定了很多东西,从点点滴滴做起,万丈高楼也是从一砖一瓦开始的

以上是关于享元模式--Flyweight的主要内容,如果未能解决你的问题,请参考以下文章

享元模式(Flyweight)

Flyweight 享元(结构型)

JAVA设计模式之享元模式(flyweight)

JAVA设计模式之享元模式(flyweight)

设计模式之享元模式 FlyWeight

享元模式(Flyweight)