• 结构类模式(六):享元(Flyweight)


    定义

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

    两个状态

    1. 内蕴状态存储在享元内部,不会随环境的改变而有所不同,是可以共享的。
    2. 外蕴状态是不可以共享的,它随环境的改变而改变的,因此外蕴状态是由客户端来保持(因为环境的变化是由客户端引起的)。

    和对象池的区别

    1. 对象池主要解决对象的复用问题,池中的每个对象都是可以替换的,从池中获取对象A和获取对象B对客户端而言都是一样的。
    2. 享元模式主要解决对象的共享问题,建立多个细粒度的可以进行共享的对象是其关注的重点。

    UML

    优点

    1. 减少运行时对象实例的个数,节省内存。
    2. 将许多“虚拟”对象的状态集中管理。

    缺点

    1. 一旦你实现了它,单个的逻辑实现将无法拥有独立而不同的行为。

    应用场景

    1. 系统中有大量对象且这些对象消耗大量内存。
    2. 这些对象的状态大部分可以外部化。
    3. 这些对象可以按照内蕴状态分为很多组,当把外蕴对象从对象中剔除出来时,每一组对象都可以用一个对象来代替。

    示例

    我们考虑一个场景,当我们需要自己实现绘制艺术字时,每一个字符都会有下面的几个状态:1.字体轮廓(这部分就是最耗内存的部分,每个字体都会有大量的数据来记录该字体的样式);2.字体字符(标志该字体用来表示哪一个字符);3.字体大小;4.字体位置。

    当我们使用该艺术字来呈现一堆文本时,如果每个字符都加载同一份轮廓则会对内存和GC造成压力。

    我们会发现对于同一个字符来说,轮廓和字符都是一致的内部状态,而大小和位置则是会变动的外部状态;我们通过使用享元模式来节省内存的使用;

    Java

     1 import java.util.HashMap;
     2 import java.util.Map;
     3 
     4 public class Main
     5 {
     6     public static void main(String[] args)
     7     {
     8         String text = "Hello World! Hello Flyweight!";
     9         for (int i = 0; i < text.length(); i++)
    10         {
    11             char c = text.charAt(i);
    12             FontFlyweight font = (FontFlyweight) FontFlyweightFactory.getFont(c);
    13             font.size = (int) ((Math.random() * 20) + 7);
    14             font.x = (int) ((Math.random() * 500));
    15             font.y = (int) ((Math.random() * 500));
    16             font.drawFont();
    17         }
    18         FontFlyweightFactory.printFontCount();
    19     }
    20 
    21     /**
    22      * 字体享元接口
    23      */
    24     public interface IFontFlyweight
    25     {
    26         /**
    27          * 绘制当前字体
    28          */
    29         void drawFont();
    30     }
    31     
    32     /**
    33      * 字体享元类
    34      */
    35     public static class FontFlyweight implements IFontFlyweight
    36     {
    37         /**
    38          * 不会改变可以共享的内部状态
    39          */
    40         public final char symbol;
    41         public final String font;
    42 
    43         /**
    44          * 频繁改变不可以共享的外部状态
    45          */
    46         public int size;
    47         public int x;
    48         public int y;
    49         
    50         public FontFlyweight(char symbol)
    51         {
    52             this.symbol = symbol;
    53             //这里一般会从硬盘读取指定的美术字的字体样式
    54             this.font = "自定义的美术字";
    55         }
    56 
    57         @Override
    58         public void drawFont()
    59         {
    60             //实际上绘制一个指定样式的矢量字符是非常复杂的,内存中需要保存该字符的所有矢量信息,会占用比较大的内存开销
    61             System.out.println("在位置(" + x + ", " + y + ")处使用字体"" + font + ""绘制"" + size + ""号尺寸的字符"" + symbol + """);
    62         }
    63     }
    64 
    65     /**
    66      * 字体享元工厂
    67      */
    68     public static class FontFlyweightFactory
    69     {
    70         private static Map<Character, IFontFlyweight> _map = new HashMap<>();
    71 
    72         /**
    73          * 根据外部状态获取对应的享元对象
    74          */
    75         public static IFontFlyweight getFont(char key)
    76         {
    77             if(_map.containsKey(key))
    78             {
    79                 return _map.get(key);
    80             }
    81             IFontFlyweight info = new FontFlyweight(key);
    82             _map.put(key, info);
    83             return info;
    84         }
    85 
    86         public static void printFontCount()
    87         {
    88             System.out.println("内存中存在的字体实例数量:" + _map.values().size());
    89         }
    90     }
    91 }
    View Code
  • 相关阅读:
    java免费空间!最简单的openshift免费空间上传代码教程!和FTP一样简单!
    医疗大数据解决方案
    十大经典排序算法的JS版
    读取某个目录下的所有图片并显示到pictureBox
    一些植物查询的网站链接
    植物野外识别速查图鉴
    Winform改变Textbox边框颜色
    Microsoft Access数据库操作类(C#)
    自定义GroupBox
    ArrayList用法整理
  • 原文地址:https://www.cnblogs.com/hammerc/p/4743793.html
Copyright © 2020-2023  润新知