享元模式---Flyweight

Posted 高高for 循环

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了享元模式---Flyweight相关的知识,希望对你有一定的参考价值。

享元模式

定义:

  • 享元模式英文称为“Flyweight Pattern”,又译为羽量级模式或者蝇量级模式
  • 享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。

应用:

说到享元模式,第一个想到的应该就是池化思想了,String常量池、数据库连接池、缓冲池等等都是享元模式的应用,所以说享元模式是池技术的重要实现方式。

  • String常量池
  • 数据库连接池
  • 线程池
  • 缓冲池

享元模式的主要目的: 是实现对象的共享,即共享池,当系统中对象多的时候可以减少内存的开销,通常与工厂模式一起使用。

结构:

在这里插入图片描述
在这里插入图片描述

数据库连接池案例

在这里插入图片描述
在这里插入图片描述

  1. 编写class 实现ConnectionPool 接口

  2. 在class构造器一次性创建10个连接,将连接保存Vector pool 中

  3. 实现getConnection 从 pool 中返回一个连接

  4. 提供将连接放回连接池中方法

ConnectionPool


class ConnectionPool {

    private Vector<Connection> pool;

    /*公有属性*/
    private String url = "jdbc:mysql://localhost:3306/jt_db";
    private String username = "root";
    private String password = "root";
    private String driverClassName = "com.mysql.jdbc.Driver";

    private int poolSize = 10;
    private static ConnectionPool instance = null;
    Connection conn = null;

    /*构造方法,做一些初始化工作*/
    public ConnectionPool() {
        pool = new Vector<Connection>(poolSize);

        for (int i = 0; i < poolSize; i++) {
            try {
                Class.forName(driverClassName);
                conn = DriverManager.getConnection(url, username, password);
                pool.add(conn);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    /* 返回连接到连接池 */
    public synchronized void release(Connection conn) {
        pool.add(conn);
    }

    /* 返回连接池中的一个数据库连接 */
    public synchronized Connection getConnection() {
        if (pool.size() > 0) {
            Connection conn = pool.get(0);
            pool.remove(conn);
            return conn;
        } else {
            return null;
        }
    }
}

测试:

public class Test01 {
    public static void main(String[] args) throws SQLException {
        //创建数据库连接池
        ConnectionPool pool = new ConnectionPool();
        //2.获取数据库连接
        Connection conn = pool.getConnection();
        //3.获取传输器
        Statement stat = conn.createStatement();
        //4.发送SQL到服务器执行并返回执行结果
        String sql = "select * from account";
        ResultSet rs = stat.executeQuery( sql );
        //5.处理结果
        while( rs.next() ) {
            int id = rs.getInt("id");
            String name = rs.getString("name");
            double money = rs.getDouble("money");
            System.out.println(id+" : "+name+" : "+money);
        }
        //6.释放资源
        pool.release(conn);

        System.out.println("TestJdbc.main()....");

    }
}

在这里插入图片描述

享元模式在JDK源码中的体现

String字符串:

Java中的String字符串当第一次使用之后,就会存在于常量池内,下次使用时可以直接从常量池内取出,不需要重复创建。具体关于String的特性,可以点击这里详细了解。

@Test
    public void test2(){
        //通过字面量定义的方式:此时的s1和s2的数据javaEE声明在方法区中的字符串常量池中。
        String s1 = "javaEE";
        String s2 = "javaEE";
        //通过new + 构造器的方式:此时的s3和s4保存的地址值,是数据在堆空间中开辟空间以后对应的地址值。
        String s3 = new String("javaEE");
        String s4 = new String("javaEE");

        System.out.println(s1 == s2);//true
        System.out.println(s1 == s3);//false
        System.out.println(s1 == s4);//false
        System.out.println(s3 == s4);//false
 
    }

在这里插入图片描述

API–05–String–特性

https://blog.csdn.net/weixin_48052161/article/details/114491159

在这里插入图片描述

Integer对象:

public class TestInteger {
    public static void main(String[] args) {
        Integer a = Integer.valueOf(10);
        Integer b = 10;
        System.out.println(a==b);

        Integer m = Integer.valueOf(128);
        Integer n = 128;
        System.out.println(m==n);
    }
}

在这里插入图片描述

  • 第1句是true,第2句输出false。这好像有点神奇,我们来看看valueOf的源码:
    在这里插入图片描述
  • 这里就是用到了享元模式,首先会去缓存里面取,但是我们看到取缓存时候有个条件,那就是数字必须在low和high之间:
    在这里插入图片描述
    可以看到low是-128,high默认是127,所以我们取128的时候就不相等了。
    当然,这里为什么限定-128~127之间才缓存,也只是个经验原因,在这个区间的数字是最常用的。

在Integer类中,包含256个Integer缓存对象,范围是 -128到127。

  • 另外还有Long中也用到了享元模式,在这里就不继续举例了。

总结:

使用场景:

  1. 系统有大量相似对象。
  2. 需要缓冲池的场景。

优点:

  1. 大大减少对象的创建
  2. 降低系统的内存
  3. 使效率提高

缺点:

  1. 提高了系统的复杂度,需要注意分离出外部状态和内部状态。
  2. 需要关注线程安全性问题

享元模式与单例模式的异同:

单例模式和享元模式都是为了避免重复创建对象,但是其本质是不一样的:

  1. 其实现方式不一样,单例是一个类只有一个唯一的实例,而享元可以有多个实例,只是通过一个共享容器来存储不同的对象。
  2. 其使用场景不一样,单例是强调减少实例化提升性能,因此一般用于一些需要频繁创建和销毁实例化对象或创建和销毁实例化对象非常消耗资源的类中,如连接池、线程池。而享元则是强调共享相同对象或对象属性,节约内存使用空间。

以上是关于享元模式---Flyweight的主要内容,如果未能解决你的问题,请参考以下文章

享元模式(Flyweight)

Flyweight 享元(结构型)

JAVA设计模式之享元模式(flyweight)

JAVA设计模式之享元模式(flyweight)

设计模式之享元模式 FlyWeight

享元模式(Flyweight)