• 《图解设计模式》读书笔记9-1 Flyweight模式


    模式简介

    Flyweight是轻量的意思,此模式将要用的对象放到“对象池”中,随取随用,不重复创建对象,达到减少对象内存占用的目的,实现了对象的“轻量”。

    在数据库连接池、字符串缓存池里面都有此模式的应用。

    此模式的中文表述为:享元模式

    示例代码

    代码功能与实现思路

    输入一个数字字符串,比如“121”,以"大型字符"形式输出出来。

    输出的“大型字符”如下所示:

    ......##........
    ..######........
    ......##........
    ......##........
    ......##........
    ......##........
    ..##########....
    ................
    ....######......
    ..##......##....
    ..........##....
    ......####......
    ....##..........
    ..##............
    ..##########....
    ................
    ......##........
    ..######........
    ......##........
    ......##........
    ......##........
    ......##........
    ..##########....
    ................
    

    一个“大型字符”就是一个很长的字符串,就是“重量级对象”,如果输入一串数字比如“1654843987461935”,把每一个数字对应的“大型字符”都创建成对象,内存占用会很可观。

    观察可知,数字串里只包含0到9共十个数字,因此可以将数字对应的“大型字符”存到一个“对象池”里,每个对象只保存一份,用的时候取出来即可。这样可以大大减少内存占用。

    类图

    代码

    BigChar:表示一个数字对应的“大型字符”,charname是数字字符,fontdata是存储“大型字符”的字符串。

    构造函数从文件里面读取“大型字符”的字符串数据保存到fontdata里面。

    public class BigChar {
        // 字符名字
        private char charname;
        // 大型字符对应的字符串(由'#' '.' '
    '组成)
        private String fontdata;
        // 构造函数
        public BigChar(char charname) {
            this.charname = charname;
            try {
                //从文件里面读取
                BufferedReader reader = new BufferedReader(
                    new FileReader("D:\" + charname + ".txt")
                );
                String line;
                StringBuffer buf = new StringBuffer();
                while ((line = reader.readLine()) != null) {
                    buf.append(line);
                    buf.append("
    ");
                }
                reader.close();
                this.fontdata = buf.toString();
            } catch (IOException e) {
                this.fontdata = charname + "?";
            }
        }
        // 显示大型字符
        public void print() {
            System.out.print(fontdata);
        }
    }
    

    BigCharFactory:“大型字符”的工厂,pool就是对象池。使用了单例模式,整个程序里面只有一个工厂,工厂里面有一个对象池,需要“大型字符”就到对象池里面取,如果对象池里面有对应的“大型字符”则直接给予,没有就创建一个再给。

    public class BigCharFactory {
        // 管理已经生成的BigChar的实例
        private HashMap pool = new HashMap();
        // Singleton模式
        private static BigCharFactory singleton = new BigCharFactory();
        // 构造函数
        private BigCharFactory() {
        }
        // 获取唯一的实例
        public static BigCharFactory getInstance() {
            return singleton;
        }
        // 生成(共享)BigChar类的实例
        public synchronized BigChar getBigChar(char charname) {
            BigChar bc = (BigChar)pool.get("" + charname);
            if (bc == null) {
                bc = new BigChar(charname); // 生成BigChar的实例
                pool.put("" + charname, bc);
            }
            return bc;
        }
    }
    

    BigString:将数字字符串以“大型字符”形式输出。

    public class BigString {
        // “大型字符”的数组
        private BigChar[] bigchars;
        // 构造函数
        public BigString(String string) {
            bigchars = new BigChar[string.length()];
            BigCharFactory factory = BigCharFactory.getInstance();
            for (int i = 0; i < bigchars.length; i++) {
                bigchars[i] = factory.getBigChar(string.charAt(i));
            }
        }
        // 显示
        public void print() {
            for (int i = 0; i < bigchars.length; i++) {
                bigchars[i].print();
            }
        }
    }
    

    Main

    public class Main {
        public static void main(String[] args) {
            BigString bs = new BigString("1212123");
            bs.print();
        }
    }
    

    结果图示分析

    模式角色和类图

    角色

    • Flyweight

    Flyweight表示那些实例会被共享的类。在本例中,由BigChar扮演此角色。

    • FlyweightFactory

    FlyweightFactory角色是生成Flyweight角色的工厂。在工厂中生成Flyweight角色可以实现实例共享。在本例中,由BigCharFactory类扮演此角色。

    • Client

    Client角色使用FlyweightFactory类的单例实例生成Flyweight角色并使用之。在本例中,由BigString类扮演此角色。

    类图

    拓展思路

    对多个地方产生影响

    共享对象,意味着一旦对象发生改变,所有引用它的地方都要变,注意这个特点,修改之前要考虑好造成的影响。

    什么要共享,什么不要共享

    应当共享的信息被称为Intrinsic,表示本质的,固有的。即不依赖于实例状态,无论在什么情况下都不会改变的信息,可以被共享。

    不应当共享的信息被称为Extrinsic,表示外在的,非本质的。即随时可能变化的信息,不应该被共享。

    垃圾回收

    如果对象占用了过多内存,JVM就要开始回收垃圾了。如果一个对象没有被任何实例引用,垃圾回收器就会认为这是个垃圾,会回收掉。在上面例子中,由于pool是HashMap,里面的共享对象始终会被pool引用,所以不会被回收。

  • 相关阅读:
    express中间件
    复习node中加载静态资源--用express+esj
    有关es6的模块化
    es6转码和package.json中的配置
    MySQL必知必会--使用子查询
    MySQL必知必会--分 组 数 据
    MySQL必知必会--汇 总 数 据
    mysql必知必会--使用数据处理函数
    拼凑可导的充分必要条件
    递推数列极限存在证明
  • 原文地址:https://www.cnblogs.com/qianbixin/p/11215574.html
Copyright © 2020-2023  润新知