这篇推文分享一下结构型模式的最后一种---享元模式
享元模式:
· 享元模式的主要目的是实现对象的共享,即共享池,当系统中对象多的时候可以减少内存的开销,通常与工厂模式一起使用。
· 内部状态:在享元对象内部不随外界环境改变而改变的共享部分。
· 外部状态:随着环境的改变而改变,不能够共享的状态就是外部状态。
· 内部状态存储于享元对象内部,而外部状态则应该由客户端来考虑。
· 享元模式的核心在于享元工厂类,享元工厂类的作用在于提供一个用于存储享元对象的享元池,用户需要对象时,首先从享元池中获取,如果享元池中不存在,则创建一个新的享元对象返回给用户,并在享元池中保存该新增对象。
形状类:
public abstract class Shape {
public abstract void draw();
public abstract void name();
}
绘制图形的具体享元类:
public class Circle extends Shape{
//内部状态共享属性
private String color;
public Circle(String color){
this.color = color;
}
public void draw() {
System.out.println("画了一个 " + color +" 的圆形");
}
public void name(CircleName cn) {
System.out.println("这个圆形叫:" + cn.get );
}
}
外部状态类(不共享):
public class CircleName{
private String name;
public CircleName(String name){
this.name = name;
}
//省略get、set
}
享元工厂类:
public class FlyweightFactory{
static Map<String, Shape> shapes = new HashMap<String, Shape>();
public static Shape getShape(String key){
Shape shape = shapes.get(key);
//如果shape==null,表示不存在,则新建,并且保持到共享池中
if(shape == null){
shape = new Circle(key);
shapes.put(key, shape);
}
return shape;
}
public static int getSum(){
return shapes.size();
}
}
测试
public class ClientTest {
public static void main(String[] args) {
Shape shape1 = FlyweightFactory.getShape("红色");
shape1.draw();
shape1.name(new CircleName("红色圆形"));//增加外部状态
Shape shape2 = FlyweightFactory.getShape("灰色");
shape2.draw();
shape2.name(new CircleName("灰色圆形"));//增加外部状态
Shape shape3 = FlyweightFactory.getShape("绿色");
shape3.draw();
shape2.name(new CircleName("绿色圆形"));//增加外部状态
System.out.println("一共绘制了"+FlyweightFactory.getSum()+"种颜色的圆形");
}
}
画了一个 红色 的圆形
这个圆形叫:红色圆形
画了一个 灰色 的圆形
这个圆形叫:灰色圆形
画了一个 绿色 的圆形
这个圆形叫:绿色圆形
一共绘制了3种颜色的圆形
数据库连接池也同样使用了这种模式:
享元模式适用于作共享的一些个对象,他们有一些共有的属性,就拿数据库连接池来说,url、driverClassName、username、password及dbname,这些属性对于每个连接来说都是一样的,所以就适合用享元模式来处理,建一个工厂类,将上述类似属性作为内部数据,其它的作为外部数据,在方法调用时,当做参数传进来,这样就节省了空间,减少了实例的数量。
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;
private static ConnectionPool instance = null;
Connection conn = null;
/*构造方法,做一些初始化工作*/
private 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() {
pool.add(conn);
}
/* 返回连接池中的一个数据库连接 */
public synchronized Connection getConnection() {
if (pool.size() > 0) {
Connection conn = pool.get(0);
pool.remove(conn);
return conn;
} else {
return null;
}
}
}
通过连接池的管理,实现了数据库连接的共享,不需要每一次都重新创建连接,节省了数据库重新创建的开销,提升了系统的性能!
优缺点:
优点:
· 享元模式的优点在于它能够极大的减少系统中对象的个数。
· 享元模式由于使用了外部状态,外部状态相对独立,不会影响到内部状态,所以享元模式使得享元对象能够在不同的环境被共享。
缺点:
· 由于享元模式需要区分外部状态和内部状态,使得应用程序在某种程度上来说更加复杂化了。
· 为了使对象可以共享,享元模式需要将享元对象的状态外部化,而读取外部状态使得运行时间变长。