• 对享元模式的理解


    一、场景

    • 有时候,一个程序要创建大量相似的对象,例如,游戏中需要渲染很多的子弹,但这些子弹除了位置不同外,其余都相同。
    • 如果我们不将相同的部分抽取出来,迟早会:Out of Memory。
    • 享元模式会将不同对象的相同数据进行缓存以节省内存。

    我理解:享元,共享元数据。
    当然了也有其他称呼:缓存、Cache、Flyweight

    1、简单的案例

    • “渲染”一片森林,森林由树组成。
    @AllArgsConstructor
    public class Tree {
        private int x;
        private int y;
        private String name;
        private String color;
    
        public int memorySize() {
            // int按1个单位估算,String按字符个数估算。
            return 2 + name.length() + color.length();
        }
    }
    
    public class Forest {
        private List<Tree> trees;
    
        public Forest() {
            trees = new ArrayList<>();
        }
    
        public void addTree(Tree tree) {
            trees.add(tree);
        }
    
        public void printMemorySize() {
            System.out.println("memory size: " + trees.stream().mapToInt(Tree::memorySize).sum());
        }
    }
    
    public class Application {
        public static void main(String[] args) {
            Forest forest = new Forest();
            forest.addTree(new Tree(1, 2, "apple tree", "red"));
            forest.addTree(new Tree(3, 4, "apple tree", "red"));
            forest.addTree(new Tree(5, 6, "apple tree", "red"));
            forest.addTree(new Tree(7, 8, "orange tree", "yellow"));
            forest.addTree(new Tree(9, 10, "orange tree", "yellow"));
            forest.addTree(new Tree(11, 12, "orange tree", "yellow"));
            forest.printMemorySize();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    memory size: 102
    
    • 1

    二、通过享元模式实现

    1、代码

    public class Tree {
        private int x;
        private int y;
        private final TreeType treeType;
    
        public Tree(int x, int y, String name, String color) {
            this.x = x;
            this.y = y;
    
            this.treeType = TreeTypeFactory.gotTreeType(name, color);
        }
    
        public int memorySize() {
            // int按1个单位估算,String按字符个数估算。
            return 2;
        }
    }
    
    @AllArgsConstructor
    public class TreeType {
        private String name;
        private String color;
    
        public int memorySize() {
            return name.length() + color.length();
        }
    }
    
    public class TreeTypeFactory {
        private static final Map<String, TreeType> treeTypeMap = new HashMap<>();
    
        public static TreeType gotTreeType(String name, String color) {
            String key = String.format("%s_%s", name, color);
            if (!treeTypeMap.containsKey(key)) {
                treeTypeMap.put(key, new TreeType(name, color));
            }
            return treeTypeMap.get(key);
        }
    
        public static int memorySize() {
            return treeTypeMap.values().stream().mapToInt(TreeType::memorySize).sum();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    public class Application {
        public static void main(String[] args) {
            Forest forest = new Forest();
            forest.addTree(new Tree(1, 2, "apple tree", "red"));
            forest.addTree(new Tree(3, 4, "apple tree", "red"));
            forest.addTree(new Tree(5, 6, "apple tree", "red"));
            forest.addTree(new Tree(7, 8, "orange tree", "yellow"));
            forest.addTree(new Tree(9, 10, "orange tree", "yellow"));
            forest.addTree(new Tree(11, 12, "orange tree", "yellow"));
            forest.printMemorySize();
        }
    }
    
    /*
    memory size: 42
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    2、个人思考

    • 初学外观模式时,我惊呼:这也算设计模式?现在学了享元模式,内心已经很平静了:有应用场景的设计模式就是好模式。
    • 享元模式的关键步骤
    • (1)将类中可以共享的数据抽取出一个享元类。
      • Tree类的(name、color)可以被共享,因此抽取为TreeType。
    • (2)在创建对象时,共享享元对象。
    public Tree(int x, int y, String name, String color) {
        this.x = x;
        this.y = y;
    
        this.treeType = TreeTypeFactory.gotTreeType(name, color);
    }  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • (3)通过工厂模式封装创建享元对象的细节:
    public class TreeTypeFactory {
        private static final Map<String, TreeType> treeTypeMap = new HashMap<>();
    
    	...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    享元模式只有一个目的: 减少内存消耗。 如果程序没有遇到内存容量不足的问题, 则可以暂时忽略该模式。

  • 相关阅读:
    前端bootstrap+fileInput+django后端文件编辑回显
    前端录入音频并上传
    ERROR (-1005)]: Host not enough! nebula无法注册元数据
    Dao、Dto、Entity和pojo、mapper概念及关系
    若依 从下载到成功运行及打包
    【接口测试】如何在 Eolink Apilkit 中使用 cookie ?
    Nginx限制每秒请求次数,限制每秒连接次数,下载速度限制
    vlc播放网络数据流
    系统架构设计师(第二版)学习笔记----多媒体技术
    微服务13:云基础场景下流量策略实现原理
  • 原文地址:https://blog.csdn.net/weixin_37477009/article/details/138010587