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


    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的复制对象的方式性能会好一些。

  • 相关阅读:
    2022年全球市场干湿两用电动剃须刀总体规模、主要生产商、主要地区、产品和应用细分研究报告
    QQ第三方登录-python_web开发_django框架
    QT多语言冷实现以及注意事项
    操作系统的发展与分类
    Java设计模式之装饰器模式(Decorator Pattern)
    无需编写一行代码,实现任何方法的流量防护能力
    入侵防御(IPS)技术,怎么做好入侵防护
    C++插入排序
    关于知识图谱(第二天)
    T1064 奥运奖牌计数(信息学一本通C++)
  • 原文地址:https://blog.csdn.net/Extraordinarylife/article/details/126688149