• 设计模式-享元模式、享元模式示例


    1、简介

    享元模式运用共享技术有效地最大限度地复用细粒度对象的一种模式。该模式中,以对象的信息状态划分,可以分为内部数据和外部数据。

    • 内部数据是对象可以共享出来的信息,这些信息不会随着系统的运行而改变;
    • 外部数据则是在不同运行时被标记了不同的值。

    享元模式一般可以分为三个角色,分别为 Flyweight(抽象享元类)、ConcreteFlyweight(具体享元类)和 FlyweightFactory(享元工厂类)。抽象享元类通常是一个接口或抽象类,向外界提供享元对象的内部数据或外部数据;具体享元类是指具体实现内部数据共享的类;享元工厂类则是主要用于创建和管理享元对象的工厂类。

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

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

    • 使用场景:

      • 系统有大量相似对象。
      • 需要缓冲池的场景。
    • 实际例子

      • String就是享元模式,创建对象如果无放到常量池中,有则直接使用,从而减少重复创建相同值对象,占用内存空间
      • 数据库连接池
      • 线程池

    2、示例

    
    /**
     * 享元模式
     */
    public class FlyweightDemo {
    
        public static void main(String[] args) {
            Flyweight fw0 = FlyweightFactory.getFlyweight("a");
            Flyweight fw1 = FlyweightFactory.getFlyweight("b");
            Flyweight fw2 = FlyweightFactory.getFlyweight("a");
            Flyweight fw3 = FlyweightFactory.getFlyweight("b");
            fw1.operation("abc");
            System.out.printf("[结果(对象对比)] - [%s]\n", fw0 == fw2);
            System.out.printf("[结果(内在状态)] - [%s]\n", fw1.getType());
        }
    }
    
    /**
     * 抽象享元类
     */
    interface Flyweight {
        // 对外状态对象
        void operation(String name);
        // 对内对象
        String getType();
    }
    
    /**
     * 具体享元类
     */
    class ConcreteFlyweight implements Flyweight {
        private String type;
    
        public ConcreteFlyweight(String type) {
            this.type = type;
        }
    
        @Override
        public void operation(String name) {
            System.out.println("类型(内在状态):"+type+",名字(外在):"+name);
        }
    
        @Override
        public String getType() {
            return type;
        }
    }
    
    /**
     * 享元工厂类
     */
    class FlyweightFactory {
        //享元池
        private static final Map<String, Flyweight> FLYWEIGHT_MAP = new HashMap<>();
    
        public static Flyweight getFlyweight(String type) {
            if (FLYWEIGHT_MAP.containsKey(type)) {
                //如果在享元池中存在对象,则直接获取
                return FLYWEIGHT_MAP.get(type);
            } else {
                // 在响应池不存在,则新创建对象, 并放入到享元池
                ConcreteFlyweight flyweight = new ConcreteFlyweight(type);
                FLYWEIGHT_MAP.put(type, flyweight);
                return flyweight;
            }
        }
    } 
    
    • 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
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    3、对比单例、原型模式

    • 享元模式可以再次创建对象 也可以取缓存对象

    • 单例模式则是严格控制单个进程中只有一个实例对象

    • 享元模式可以通过自己实现对外部的单例 也可以在需要的使用创建更多的对象

    • 单例模式是自身控制 需要增加不属于该对象本身的逻辑

    • 原型模式中相对new来说,clone少了调用构造函数。如果构造函数中存在大量属性初始化或大对象,则使用clone的复制对象的方式性能会好一些。

  • 相关阅读:
    LocalDateTime获取时间类(当前时间)
    【ELK05】es的java-api操作-Java High Level REST Client常用功能
    Vue3+node.js网易云音乐实战项目(三)
    offsetWidth / offsetHeight等
    Mybatis+startPage()+动态 orderBy执行sql报错
    详解OpenCV的函数imread()和函数imshow(),并利用它们实现对图像的读取和显示
    【编译原理】类型检查
    git切换源失败解决方案
    史上最简SLAM零基础解读(8) - g2o(图优化)→示例代码讲解
    requests.sessions.Session() 和 requests.Session()是相同的
  • 原文地址:https://blog.csdn.net/Extraordinarylife/article/details/126688149