• 详解设计模式:享元模式


    享元模式(Flyweight Pattern),是对象池的一种体现,也是 GoF 的 23 种设计模式中的一种结构型设计模式。

    享元模式 主要用于减少创建对象的数量,以减少内存占用和提高性能。它提供了减少对象数量从而改善应用所需的对象结构的方式。

    享元模式 尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象。

    ~

    本篇内容包括:关于享元模式、享元模式 Demo



    一、关于享元模式

    1、关于享元模式

    享元模式(Flyweight Pattern),是对象池的一种体现,也是 GoF 的 23 种设计模式中的一种结构型设计模式。

    享元模式 主要用于减少创建对象的数量,以减少内存占用和提高性能。它提供了减少对象数量从而改善应用所需的对象结构的方式。

    享元模式 尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象。

    2、关于享元模式的构成

    享元模式主要包含四种角色:

    1. 抽象享元(Flyweight)角色:是所有的具体享元类的基类,为具体享元规范需要实现的公共接口,非享元的外部状态以参数的形式通过方法传入。
    2. 具体享元(Concrete Flyweight)角色:实现抽象享元角色中所规定的接口。
    3. 非享元(Unsharable Flyweight)角色:是不可以共享的外部状态,它以参数的形式注入具体享元的相关方法中。
    4. 享元工厂(Flyweight Factory)角色:负责创建和管理享元角色。当客户对象请求一个享元对象时,享元工厂检査系统中是否存在符合要求的享元对象,如果存在则提供给客户;如果不存在的话,则创建一个新的享元对象。
    3、关于享元模式的XML
    享元模式
    4、关于享元模式的应用场景

    当系统中多处需要同一组信息时,可以吧这些信息封装到一个对象中,然后对该对象进行缓存,这样,一个对象就可以提供给多处需要使用的地方,避免大量同一对象多次创建,消耗大量内存空间。
    享元模式其实就是工厂模式的一个改进机制,享元模式同样要求创建一个或一组对象,并且就是通过工厂方法生成对象的,只不过享元模式中为工厂方法增加了缓存这一功能。主要总结为以下应用场景:

    1. 常常应用于系统底层的开发,以便解决系统的性能问题。
    2. 系统有大量相似的对象、需要缓存池的场景。

    在生活中的享元模式也很常见,比如中介机构的房源共享,再比如全国社保联网。

    5、关于享元模式在 Java 中的应用

    在 Java 中最直观的享元模式就是在 Boolean,Byte,Integer,Long,Character 这些包装类中,他们都提供了valueOf()方法。

    比如:Long 的 valueOf() 方法会缓存数值 -127~128 之间的 Long 对象,在这个范围之间就会直接在这个里面去取,大于这个范围才会去 new Long 对象

    public static Long valueOf(long l) {
            final int offset = 128;
            if (l >= -128 && l <= 127) { // will cache
                return LongCache.cache[(int)l + offset];
            }
            return new Long(l);
        }
    
    private static class LongCache {
            private LongCache(){}
    
            static final Long cache[] = new Long[-(-128) + 127 + 1];
    
            static {
                for(int i = 0; i < cache.length; i++)
                    cache[i] = new Long(i - 128);
            }
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    Byte,Short,Long 的范围是 -127~128 之间。

    Character 是 0~127 之间。

    Integer 是 -127~128 之间,最小值不能改变,但是最大值可以通过虚拟机参数进行改变。-Djava.long.Intger.IntegerCache.high 来改变

    Boolean 缓存了 TRUE 和 FALSE

    6、关于享元模式的优缺点

    # 享元模式的优点:

    1. 减少对象的创建,降低内存中对象的数量,降低系统的内存,提高效率;
    2. 减少内存之外的其它资源占用。

    # 享元模式的缺点:

    1. 关注内、外部状态、关注线程安全问题;
    2. 使系统、程序复杂化。

    二、享元模式 Demo

    1、Demo 设计

    俄罗斯方块有不同的形状,我们可以对这些形状向上抽取出 AbstractBox,用来定义共性的属性和行为。

    接下来就是定义不同的形状了,IBox类、LBox类、TBox类等。

    提供了一个工厂类(BoxFactory),用来管理享元对象(也就是 AbstractBox 子类对象),该工厂类对象只需要一个,所以可以使用单例模式。并给工厂类提供一个获取形状的方法。

    2、Demo 实现

    # AbstractBox 抽象享元角色

    public abstract class AbstractBox {
        public abstract String getShape();
    
        public void display(String color) {
            System.out.println("方块形状:" + this.getShape() + " 颜色:" + color);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    # IBox/LBox/TBox 具体享元角色

    public class IBox extends AbstractBox {
    
        @Override
        public String getShape() {
            return "I";
        }
    }
    
    public class LBox extends AbstractBox {
    
        @Override
        public String getShape() {
            return "L";
        }
    }
    
    public class TBox extends AbstractBox {
    
        @Override
        public String getShape() {
            return "T";
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    # BoxFactory 享元工厂

    public class BoxFactory {
    
        private static HashMap<String, AbstractBox> map;
    
        private BoxFactory() {
            map = new HashMap<String, AbstractBox>();
            AbstractBox iBox = new IBox();
            AbstractBox lBox = new LBox();
            AbstractBox oBox = new OBox();
            map.put("I", iBox);
            map.put("L", lBox);
            map.put("O", oBox);
        }
    
        public static final BoxFactory getInstance() {
            return SingletonHolder.INSTANCE;
        }
    
        private static class SingletonHolder {
            private static final BoxFactory INSTANCE = new BoxFactory();
        }
    
        public AbstractBox getBox(String key) {
            return map.get(key);
        }
    }
    
    • 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
  • 相关阅读:
    java学习路线小白——架构师
    举个栗子~Tableau 技巧(245):用辅助标识快速查看标靶图
    Metabase学习教程:视图-1
    勒索病毒最新变种.mallab勒索病毒来袭,如何恢复受感染的数据?
    JDBC调用存储过程
    web网页大作业:基于html设计与实现的茶文化网站12页(带psd)
    SAP RANGES定义及管理使用
    token的使用
    做自动化测试选择Python还是Java?
    RocketMQ Topic/Group/Tags介绍
  • 原文地址:https://blog.csdn.net/weixin_45187434/article/details/128136268