享元模式(Flyweight Pattern)是一种结构型设计模式,旨在通过共享对象以减少内存使用和提高性能。它主要用于处理大量细粒度对象的场景,通过共享相同或相似对象来减少内存占用。
主要角色:
享元工厂(Flyweight Factory): 负责创建和管理享元对象。它确保共享对象的正确性和一致性,通常使用工厂方法或者其他创建方法。
抽象享元(Flyweight): 定义享元对象的接口,描述对象应该具有的方法。通常包括具有内部状态和外部状态的方法,内部状态是可以共享的,外部状态是不可共享的。
具体享元(Concrete Flyweight): 实现抽象享元接口,存储内部状态,并负责处理外部状态。具体享元对象需要被共享,因此它通常是不可变的。
非共享具体享元(Unshared Concrete Flyweight): 并非所有享元对象都需要被共享,有时候可以创建不可共享的具体享元对象。
工作原理:
内部状态和外部状态: 在享元模式中,对象的状态分为内部状态和外部状态。内部状态是存储在享元对象内部并可以被共享的状态,而外部状态是存储在客户端并且不能被共享的状态。
共享对象: 享元模式通过共享相同的享元对象来减少内存占用。如果一个请求可以被相同或相似对象满足,那么可以返回一个已经存在的享元对象,而不是创建一个新的对象。
客户端: 客户端负责维护外部状态,并将外部状态传递给享元对象。客户端通常使用享元工厂来获取或创建享元对象。
优缺点:
优点:
减少内存占用: 通过共享相同的享元对象,减少了大量细粒度对象的内存占用。
提高性能: 减少了创建和销毁对象的开销,提高了系统的性能。
缺点:
示例代码:
以下是一个简单的 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 是享元工厂,负责创建和管理享元对象。客户端通过工厂获取享元对象,然后调用对象的操作方法。在这个过程中,如果请求的享元对象已经存在,工厂将返回现有的对象,否则创建一个新的对象。
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 成功归还连接池,有借有还再借不难!