设计模式之享元模式

1. 享元模式概述

享元模式(Flyweight Pattern)是一种结构型设计模式,旨在通过共享对象以减少内存使用和提高性能。它主要用于处理大量细粒度对象的场景,通过共享相同或相似对象来减少内存占用。

  • 主要角色:

    1. 享元工厂(Flyweight Factory): 负责创建和管理享元对象。它确保共享对象的正确性和一致性,通常使用工厂方法或者其他创建方法。

    2. 抽象享元(Flyweight): 定义享元对象的接口,描述对象应该具有的方法。通常包括具有内部状态和外部状态的方法,内部状态是可以共享的,外部状态是不可共享的。

    3. 具体享元(Concrete Flyweight): 实现抽象享元接口,存储内部状态,并负责处理外部状态。具体享元对象需要被共享,因此它通常是不可变的。

    4. 非共享具体享元(Unshared Concrete Flyweight): 并非所有享元对象都需要被共享,有时候可以创建不可共享的具体享元对象。

  • 工作原理:

    1. 内部状态和外部状态: 在享元模式中,对象的状态分为内部状态和外部状态。内部状态是存储在享元对象内部并可以被共享的状态,而外部状态是存储在客户端并且不能被共享的状态。

    2. 共享对象: 享元模式通过共享相同的享元对象来减少内存占用。如果一个请求可以被相同或相似对象满足,那么可以返回一个已经存在的享元对象,而不是创建一个新的对象。

    3. 客户端: 客户端负责维护外部状态,并将外部状态传递给享元对象。客户端通常使用享元工厂来获取或创建享元对象。

  • 优缺点:

    • 优点:

      1. 减少内存占用: 通过共享相同的享元对象,减少了大量细粒度对象的内存占用。

      2. 提高性能: 减少了创建和销毁对象的开销,提高了系统的性能。

    • 缺点:

    1. 共享对象可能引入复杂性: 当需要考虑共享对象的线程安全性时,可能引入额外的同步机制,增加了系统的复杂性。

示例代码:
以下是一个简单的 Java 示例代码,演示了享元模式的基本结构:

import java.util.HashMap;
import java.util.Map;

// 抽象享元接口
interface Flyweight {
    void operation(String externalState);
}

// 具体享元类
class ConcreteFlyweight implements Flyweight {
    private String intrinsicState;

    public ConcreteFlyweight(String intrinsicState) {
        this.intrinsicState = intrinsicState;
    }

    @Override
    public void operation(String externalState) {
        System.out.println("ConcreteFlyweight: Intrinsic State - " + intrinsicState +
                           ", External State - " + externalState);
    }
}

// 享元工厂类
class FlyweightFactory {
    private Map<String, Flyweight> flyweights = new HashMap<>();

    public Flyweight getFlyweight(String key) {
        if (!flyweights.containsKey(key)) {
            flyweights.put(key, new ConcreteFlyweight(key));
        }
        return flyweights.get(key);
    }
}

public class FlyweightPatternExample {
    public static void main(String[] args) {
        FlyweightFactory factory = new FlyweightFactory();

        Flyweight flyweight1 = factory.getFlyweight("A");
        flyweight1.operation("1");

        Flyweight flyweight2 = factory.getFlyweight("B");
        flyweight2.operation("2");

        Flyweight flyweight3 = factory.getFlyweight("A");
        flyweight3.operation("3");
    }
}

在这个示例中,ConcreteFlyweight 表示具体的享元对象,FlyweightFactory 是享元工厂,负责创建和管理享元对象。客户端通过工厂获取享元对象,然后调用对象的操作方法。在这个过程中,如果请求的享元对象已经存在,工厂将返回现有的对象,否则创建一个新的对象。

2. 享元模式模拟实现JDBC连接池

package com.test;

import java.sql.*;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicIntegerArray;

/**
 * @author 曹见朋
 * @create 2023-11-11-14:55
 */
public class MyJDBCPool {

    public static void main(String[] args) {
        MyJDBCPool myJDBCPool =new MyJDBCPool(2);
        for (int i = 0; i < 5; i++) {
            new Thread(()->{
                Connection borrow = myJDBCPool.borrow();
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                myJDBCPool.free(borrow);
            }).start();
        }
    }


    // 1. 连接池大小
    private final int poolSize;

    // 2.连接对象数组
    private Connection[] connection;

    // 3. 连接状态 0空闲   1繁忙
    private AtomicIntegerArray states;

    // 4. 构造方法
    public MyJDBCPool(int poolSize) {
        this.poolSize = poolSize;
        this.connection=new Connection[poolSize];
        this.states=new AtomicIntegerArray(new int[poolSize]);
        for (int i = 0; i < poolSize; i++) {
            connection[i] = new MockConnection("傻狗"+i);
        }
    }

    // 5. 借连接
    public Connection borrow(){
        while(true){
            for (int i = 0; i < poolSize; i++) {
                //判断是否有空闲连接
                if (states.get(i) == 0) {
                    if (states.compareAndSet(i,0,1)) {
                        System.out.println(Thread.currentThread().getName()+" 成功获取连接池,可喜可贺!");
                        return connection[i];
                    }
                }
            }
            // 如果没有空闲连接
            synchronized (this) {
                try {
                    System.err.println(Thread.currentThread().getName()+" 没有获取连接池,正在等待!");
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    // 6. 归还连接
    public void free(Connection conn){
        for (int i = 0; i < poolSize; i++) {
            if(connection[i] == conn){
                states.set(i,0);
                System.out.println(Thread.currentThread().getName()+" 成功归还连接池,有借有还再借不难!");
                synchronized (this) {
                    this.notifyAll();
                }
                break;
            }
        }
    }
}

class MockConnection implements  Connection{

    private String name;

    public MockConnection(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "MockConnection{" +
                "name='" + name + '\'' +
                '}';
    }

    @Override
    public Statement createStatement() throws SQLException {
        return null;
    }

    @Override
    public PreparedStatement prepareStatement(String sql) throws SQLException {
        return null;
    }

    @Override
    public CallableStatement prepareCall(String sql) throws SQLException {
        return null;
    }

    @Override
    public String nativeSQL(String sql) throws SQLException {
        return null;
    }

    @Override
    public void setAutoCommit(boolean autoCommit) throws SQLException {

    }

    @Override
    public boolean getAutoCommit() throws SQLException {
        return false;
    }

    @Override
    public void commit() throws SQLException {

    }

    @Override
    public void rollback() throws SQLException {

    }

    @Override
    public void close() throws SQLException {

    }

    @Override
    public boolean isClosed() throws SQLException {
        return false;
    }

    @Override
    public DatabaseMetaData getMetaData() throws SQLException {
        return null;
    }

    @Override
    public void setReadOnly(boolean readOnly) throws SQLException {

    }

    @Override
    public boolean isReadOnly() throws SQLException {
        return false;
    }

    @Override
    public void setCatalog(String catalog) throws SQLException {

    }

    @Override
    public String getCatalog() throws SQLException {
        return null;
    }

    @Override
    public void setTransactionIsolation(int level) throws SQLException {

    }

    @Override
    public int getTransactionIsolation() throws SQLException {
        return 0;
    }

    @Override
    public SQLWarning getWarnings() throws SQLException {
        return null;
    }

    @Override
    public void clearWarnings() throws SQLException {

    }

    @Override
    public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
        return null;
    }

    @Override
    public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
        return null;
    }

    @Override
    public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
        return null;
    }

    @Override
    public Map<String, Class<?>> getTypeMap() throws SQLException {
        return null;
    }

    @Override
    public void setTypeMap(Map<String, Class<?>> map) throws SQLException {

    }

    @Override
    public void setHoldability(int holdability) throws SQLException {

    }

    @Override
    public int getHoldability() throws SQLException {
        return 0;
    }

    @Override
    public Savepoint setSavepoint() throws SQLException {
        return null;
    }

    @Override
    public Savepoint setSavepoint(String name) throws SQLException {
        return null;
    }

    @Override
    public void rollback(Savepoint savepoint) throws SQLException {

    }

    @Override
    public void releaseSavepoint(Savepoint savepoint) throws SQLException {

    }

    @Override
    public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
        return null;
    }

    @Override
    public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
        return null;
    }

    @Override
    public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
        return null;
    }

    @Override
    public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
        return null;
    }

    @Override
    public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
        return null;
    }

    @Override
    public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
        return null;
    }

    @Override
    public Clob createClob() throws SQLException {
        return null;
    }

    @Override
    public Blob createBlob() throws SQLException {
        return null;
    }

    @Override
    public NClob createNClob() throws SQLException {
        return null;
    }

    @Override
    public SQLXML createSQLXML() throws SQLException {
        return null;
    }

    @Override
    public boolean isValid(int timeout) throws SQLException {
        return false;
    }

    @Override
    public void setClientInfo(String name, String value) throws SQLClientInfoException {

    }

    @Override
    public void setClientInfo(Properties properties) throws SQLClientInfoException {

    }

    @Override
    public String getClientInfo(String name) throws SQLException {
        return null;
    }

    @Override
    public Properties getClientInfo() throws SQLException {
        return null;
    }

    @Override
    public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
        return null;
    }

    @Override
    public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
        return null;
    }

    @Override
    public void setSchema(String schema) throws SQLException {

    }

    @Override
    public String getSchema() throws SQLException {
        return null;
    }

    @Override
    public void abort(Executor executor) throws SQLException {

    }

    @Override
    public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {

    }

    @Override
    public int getNetworkTimeout() throws SQLException {
        return 0;
    }

    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        return null;
    }

    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return false;
    }
}

打印结果如下:

Thread-2 没有获取连接池,正在等待!
Thread-4 没有获取连接池,正在等待!
Thread-3 没有获取连接池,正在等待!
Thread-0 成功获取连接池,可喜可贺!
Thread-1 成功获取连接池,可喜可贺!
Thread-0 成功归还连接池,有借有还再借不难!
Thread-1 成功归还连接池,有借有还再借不难!
Thread-4 成功获取连接池,可喜可贺!
Thread-3 成功获取连接池,可喜可贺!
Thread-2 没有获取连接池,正在等待!
Thread-2 没有获取连接池,正在等待!
Thread-4 成功归还连接池,有借有还再借不难!
Thread-3 成功归还连接池,有借有还再借不难!
Thread-2 成功获取连接池,可喜可贺!
Thread-2 成功归还连接池,有借有还再借不难!

你可能感兴趣的:(设计模式,设计模式,享元模式)