JAVA设计模式——享元模式

享元模式是一种结构型设计模式。享元模式的思想是:以共享的方式高效地支持大量的细粒度对象。简单来说就是共享池的思想,如连接池、线程池、字符串常量池等。

享元模式涉及3个角色:

  • 抽象享元(Flyweight):需要被共享的对象的抽象接口。
  • 具体享元(Concrete Flyweight):需要被共享的实体对象。
  • 享元工厂(Flyweight Factory):集中管理共享对象并为客户提供共享对象的工厂,也就是共享池。

下面以一个伪JDBC连接池为例演示享元模式的实现。

抽象享元、具体享元:

public interface Connection {
    void showInfo(); // 显示连接信息的方法
}

public class ConcreteConnection implements Connection {
    private String driver;
    private String url;
    private String user;
    private String password;

    public ConcreteConnection(String driver, String url, String user, String password) {
        this.driver = driver;
        this.url = url;
        this.user = user;
        this.password = password;
    }

    @Override
    public void showInfo() {
        System.out.printf("Conn[driver=%s; url=%s; user=%s; password=%s]\n",
                driver, url, user, password);
    }
    // Getters and Setters
    // ...

    // 重写hashCode()
    // ...

    // 重写equals():所有属性相等同返回true
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        ConcreteConnection that = (ConcreteConnection) o;

        return (driver != null ? driver.equals(that.driver) : that.driver == null) 
                && (url != null ? url.equals(that.url) : that.url == null) 
                && (user != null ? user.equals(that.user) : that.user == null) 
                && (password != null ? password.equals(that.password) : that.password == null);
    }
}

享元工厂(连接池):

public class Pool {
    private Stack<Connection> stack = new Stack<>();
    private Connection sample; // 保存一个连接样本作参照
    private int size; // 连接池大小

    // 初始化连接池
    public Pool(int size, String driver, String url, String user, String password) {
        this.size = size;
        for (int i = 0; i < size; i++) {
            Connection conn = new ConcreteConnection(driver, url, user, password);
            stack.push(conn);
        }
        this.sample = stack.peek();
    }

    // 从连接池中获取一个连接
    public Connection getConnection() {
        return stack.isEmpty() ? null : stack.pop();
    }

    // 归还一个连接给连接池
    public void release(Connection conn) {
        if (stack.size() == size) // 超过连接池大小
            throw new RuntimeException("pool is full!");
        if (!conn.equals(this.sample)) // 要归还的连接与池中的连接不一样
            throw new RuntimeException("this conn is not a Flyweight");
        stack.push(conn);
    }

    // 获取连接池中剩余连接的数量
    public int getRestCount() {
        return stack.size();
    }

    // Getters and Setters
    // 这里,作为实际实现功能的集合不对外公开
    public int getSize() {
        return size;
    }

    public void setSize(int size) {
        this.size = size;
    }
}

测试:

public class FlyweightTest {
    public static void main(String[] args) {
        Pool pool = new Pool(5, "mysql", "127.0.0.1:3306", "test", "123");
        Connection conn1 = pool.getConnection();
        Connection conn2 = pool.getConnection();
        conn1.showInfo();
        conn2.showInfo();
        System.out.printf("connection rest in pool: %d\n", pool.getRestCount());
        pool.release(conn1);
        System.out.printf("connection rest in pool: %d\n", pool.getRestCount());
    }
}

运行结果:

Conn[driver=mysql; url=127.0.0.1:3306; user=test; password=123]
Conn[driver=mysql; url=127.0.0.1:3306; user=test; password=123]
connection rest in pool: 3
connection rest in pool: 4

结构图:
这里写图片描述


下面给出另一种形式实现的代码演示,这种形式是类似于字符串常量池的实现形式,注意与上面的例子比较。

享元:

public interface Shape {
    void draw();
}

public class Circle implements Shape {
    private double radius;
    private Color color;

    public Circle(double radius, Color color) {
        this.radius = radius;
        this.color = color;
    }

    @Override
    public void draw() {
        System.out.printf("Circle[radius=%f, color=%s]\n", radius, color);
    }

    // Getters and Setters
    // ...
}

享元工厂(共享池):

public class CirclePool {
    private Map<Color, Shape> map = new HashMap<>(); // 实现共享池功能的数据结构。这里以颜色作为标识,共享颜色相同的圆形对象。

    // 从共享池中获取一个圆形对象
    public Shape getCircle(double radius, Color color) {
        Shape c = map.get(color);
        if (c == null) {
            // 如果池里没有,则实例化一个,并放入池中
            c = new Circle(radius, color);
            map.put(color, c);
        }
        return c;
    }

    public void count() {
        System.out.printf("size of pool: %d\n", map.size());
    }
}

// 测试
class CirclePoolTest {
    public static void main(String[] args) {
        CirclePool pool = new CirclePool();
        pool.count();

        Shape c1 = pool.getCircle(1, Color.RED);
        c1.draw();
        Shape c2 = pool.getCircle(1, Color.VIOLET);
        c2.draw();
        pool.count();

        Shape c3 = pool.getCircle(2, Color.RED);
        c3.draw();
        pool.count();
    }
}

运行结果:

size of pool: 0
Circle[radius=1.000000, color=RED]
Circle[radius=1.000000, color=VIOLET]
size of pool: 2
Circle[radius=1.000000, color=RED]
size of pool: 2

结构图:
这里写图片描述


享元模式大大减少了对象的创建,降低系统的内存消耗,使效率提高。

但同时,享元模式提高了系统的复杂度,需要分离出外部状态和内部状态,而且外部状态具有固有化的性质,不应该随着内部状态的变化而变化,否则会造成系统的混乱。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值