java设计模式之享元模式
享元模式的定义:
享元模式又叫作轻量级模式,是对象池的一种实现。类似线程池,线程池可以避免不停的创建和销毁多个对象,消耗性能。
享元模式提供了减少对象数量从而改善应用所需的对象结构的方式。其宗旨是共享细粒度的对象,将多个对同一对象的访问集
中起来,不必为每个访问者都创建单独的对象,以此来降低内存的消耗,属于结构型设计模式。
享元模式的应用场景:
- 常应用于系统底层的开发,以便解决系统的性能问题。
- 系统有大量相似对象、需要缓冲池场景。
享元模式的UML类图:
由上图可以看到,享元模式主要包含3个角色。
- 抽象享元角色(IFlyweight):享元对象抽象基类或者接口,同时定义出对象的外部状态和内部状态的接口实现。
- 具体享元角色(ConcreteFlyweight):实现抽象角色定义的业务。该角色的内部状态处理应用与环境无关,不会出现一个操作改变内部状态、同时修改了外部状态的情况。
- 享元工厂(FlyweightFactory):负责管理享元对象池和创建享元对象。
享元模式的通用写法:
package com.gupaoedu.vip.pattern.flyweight.general; import java.util.HashMap; import java.util.Map; /* * * @Author liuyi * @Description //TODO * @Date 2020/11/15 13:13 * @Param * @return **/ public class Client { public static void main(String[] args) { FlyweightFactory flyweightFactory = new FlyweightFactory(); IFlyweight flyweight1 = flyweightFactory.getFlyweight("aa"); IFlyweight flyweight2 = flyweightFactory.getFlyweight("bb"); flyweight1.operation("a"); flyweight2.operation("b"); } interface IFlyweight { void operation(String extrinsicState); } // 具体享元角色 static class ConcreteFlyweight implements IFlyweight { private String intrinsicState; public ConcreteFlyweight(String intrinsicState) { this.intrinsicState = intrinsicState; } public void operation(String extrinsicState) { System.out.println("Object address: " + System.identityHashCode(this)); System.out.println("IntrinsicState: " + this.intrinsicState); System.out.println("ExtrinsicState: " + extrinsicState); } } // 享元工厂 static class FlyweightFactory { private static Map<String, IFlyweight> pool = new HashMap<String, IFlyweight>(); // 因为内部状态具备不变性,因此作为缓存的键 public static IFlyweight getFlyweight(String intrinsicState) { if (!pool.containsKey(intrinsicState)) { IFlyweight flyweight = new ConcreteFlyweight(intrinsicState); pool.put(intrinsicState, flyweight); } return pool.get(intrinsicState); } } }
使用享元模式实现简单的数据库连接池:
我们在用java'操作数据库的时候,首先必须要创建Connection和数据建立连接,才能操作数据库,而创建和关闭连接都十分的
消耗性能。所以数据库连接池就产生了,它的基本原理是将Connection对象缓冲起来,每次取得时候从缓冲中取,用完之后再放回
缓冲中,达到资源重复利用得目的,代码如下:
package com.gupaoedu.vip.pattern.flyweight.pool; import java.sql.Connection; import java.sql.DriverManager; import java.util.Vector; /* * * @Author liuyi * @Description //TODO * @Date 2020/11/15 13:34 * @Param * @return **/ public class ConnectionPool { private Vector<Connection> pool; private String url = "jdbc:mysql://localhost:3306/test"; private String username = "root"; private String password = "root"; private String driverClassName = "com.mysql.jdbc.Driver"; private int poolSize = 100; public ConnectionPool() { pool = new Vector<Connection>(poolSize); try{ Class.forName(driverClassName); for (int i = 0; i < poolSize; i++) { Connection conn = DriverManager.getConnection(url,username,password); pool.add(conn); } }catch (Exception e){ e.printStackTrace(); } } public synchronized Connection getConnection(){ if(pool.size() > 0){ Connection conn = pool.get(0); pool.remove(conn); return conn; } return null; } public synchronized void release(Connection conn){ pool.add(conn); } }
享元模式得内部状态和外部状态:
享元模式得定义提出两个要求:细粒度和共享对象。因为要求细粒度,所以不可避免地会使对象数量多且性质相近,此时我们就将这些对象地信息
分为两个部分:内部状态和外部状态。
内部状态指对象共享出来地信息,存储在享元对象内部,并且不会随环境地改变而改变。外部状态指对象得以依赖地一个标记,随环境地改变而改变
不可共享。
比如连接池中的连接对象,保存了连接对象的用户名,密码,URL等信息,在创建对象的时候就设置好了,不会随着环境的改变而改变,所以这些属
于内部状态。而当每个连接要被收回利用时,我们需要将它标记为可用状态,这些属于外部状态。
享元模式的优点:
- 减少对象的创建,降低内存中对象的数量,降低系统的内存消耗,提高效率。
- 减少内存之外的其他资源占用。
享元模式的缺点:
- 需要关注内、外部状态,关注线程安全问题。
- 使系统、程序的逻辑复杂化。