您的位置:首页 > 健康 > 养生 > 手机浏览器网址导航_dw制作电商网页_网站排名优化服务_百度平台官网

手机浏览器网址导航_dw制作电商网页_网站排名优化服务_百度平台官网

2024/10/7 6:38:28 来源:https://blog.csdn.net/qq_44732500/article/details/142258985  浏览:    关键词:手机浏览器网址导航_dw制作电商网页_网站排名优化服务_百度平台官网
手机浏览器网址导航_dw制作电商网页_网站排名优化服务_百度平台官网

🎯 设计模式专栏,持续更新中
欢迎订阅:JAVA实现设计模式
🛠️ 希望小伙伴们一键三连,有问题私信都会回复,或者在评论区直接发言

享元模式

享元模式(Flyweight Pattern) 是一种结构型设计模式,旨在通过共享细粒度对象来减少内存使用和对象创建的开销。享元模式可以在系统中重复使用多个相同或相似的对象,通过避免重复创建相同的对象来提高性能,特别是在大量对象需要频繁创建时,享元模式能够极大减少内存消耗。

核心思想:

享元模式将对象分为内部状态外部状态,其中内部状态可以被共享,而外部状态则由外部提供。通过共享内部状态对象,可以避免创建大量类似的对象。

关键点:

  • 内部状态:可以被共享的状态,不会随着环境改变。
  • 外部状态:根据具体场景变化的状态,通常通过外部传递给享元对象。
  • 享元工厂:用于管理和维护享元对象的共享,确保重复对象不会多次创建。

享元模式的原理类图

在这里插入图片描述

  1. FlyWeight 是抽象的享元角色, 他是产品的抽象类, 同时定义出对象的外部状态和内部状态的接口或实现
  2. ConcreteFlyWeight 是具体的享元角色,是具体的产品类,实现抽象角色定义相关业务
  3. UnSharedConcreteFlyWeight 是不可共享的角色,一般不会出现在享元工厂。
  4. FlyWeightFactory 享元工厂类,用于构建一个池容器(集合), 同时提供从池中获取对象方法

生动的案例:图形绘制系统 🎨

假设我们正在开发一个图形绘制系统,需要在屏幕上绘制大量的圆形(Circle)。每个圆形都有颜色、半径、位置等属性。为了提高性能,我们使用享元模式,共享相同颜色的圆形对象,避免重复创建相同颜色的圆形。

  • 共享对象:具有相同颜色的圆形可以共享。
  • 外部状态:圆形的半径和位置(这些信息是具体到每个圆形的,不能共享)

代码实现

Step 1: 创建 Flyweight 接口

定义享元模式的接口,draw() 方法接收外部状态。

// 享元抽象类
public interface Flyweight {void draw(int x, int y, int radius); // 外部状态为位置和半径
}

Step 2: 实现具体的 Flyweight

实现 Flyweight 接口,ConcreteFlyweight 包含共享的颜色属性。

// 具体享元类
public class ConcreteFlyweight implements Flyweight {private final String color; // 共享的内部状态public ConcreteFlyweight(String color) {this.color = color;}@Overridepublic void draw(int x, int y, int radius) {System.out.println("Drawing a " + color + " circle at (" + x + ", " + y + ") with radius " + radius);}
}

Step 3: 实现享元工厂类

工厂类负责管理共享的 Flyweight 对象,确保同样颜色的圆形只创建一次。

public class FlyweightFactory {private static final Map<String, Flyweight> flyweights = new HashMap<>();public static Flyweight getFlyweight(String color) {Flyweight flyweight = flyweights.get(color);if (flyweight == null) {flyweight = new ConcreteFlyweight(color);flyweights.put(color, flyweight);System.out.println("Creating a " + color + " flyweight.");}return flyweight;}public static int getFlyweightCount(){return flyweights.size();}
}

Step 4: 客户端使用享元模式

客户端通过工厂获取 Flyweight 对象,并传入外部状态(位置和半径)。

public class Client {public static void main(String[] args) {Flyweight circle1 = FlyweightFactory.getFlyweight("Red");circle1.draw(10, 10, 5);Flyweight circle2 = FlyweightFactory.getFlyweight("Red");circle2.draw(20, 20, 10);Flyweight circle3 = FlyweightFactory.getFlyweight("Blue");circle3.draw(15, 15, 7);Flyweight circle4 = FlyweightFactory.getFlyweight("Red");circle4.draw(30, 30, 15);System.out.println("-------------------------------------");System.out.println("Total number of flyweights: " + FlyweightFactory.getFlyweightCount());}
}

输出结果

Creating a Red flyweight.
Drawing a Red circle at (10, 10) with radius 5
Drawing a Red circle at (20, 20) with radius 10
Creating a Blue flyweight.
Drawing a Blue circle at (15, 15) with radius 7
Drawing a Red circle at (30, 30) with radius 15
-------------------------------------
Total number of flyweights: 2

享元模式在源码中的应用

享元模式广泛应用于 Java 标准库和一些优秀的开源框架中,主要用于优化性能、减少内存占用。以下是几个使用了享元模式的经典例子:

1. Java 中的 String 常量池

Java 中的 String 类型是享元模式最典型的应用之一。String 类在 Java 中是不可变的,JVM 会在字符串常量池中缓存相同的字符串对象,以避免重复创建相同内容的字符串,从而节省内存空间。

享元模式的应用

  • 内部状态:字符串内容(相同的字符串内容可以被共享)。
  • 外部状态:无(因为 String 是不可变的,所有内容都可以共享)

示例代码

public class StringFlyweightExample {public static void main(String[] args) {String s1 = "Hello";String s2 = "Hello";// s1 和 s2 是同一个对象,因为 JVM 在常量池中共享了 "Hello"System.out.println(s1 == s2);  // 输出 true// 通过 new 关键字创建新的字符串对象,不会使用常量池String s3 = new String("Hello");System.out.println(s1 == s3);  // 输出 false}
}

JVM 通过字符串常量池优化内存使用,避免重复创建相同内容的字符串。如果想看更深度解读String,请看这篇文章 https://blog.csdn.net/qq_44732500/article/details/141884904

2.Java 中的 Integer 缓存池

Integer 类中也使用了享元模式,对**-128 到 127 之间的整数**进行了缓存。这意味着当我们创建这些范围内的 Integer 对象时,它们将被共享,而不是每次都创建新对象。

享元模式的应用

  • 内部状态:整数值(-128 到 127 之间的整数被缓存共享)。
  • 外部状态:无(这些整数是不可变的)。

源码片段

public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);
}

示例代码

public class IntegerFlyweightExample {public static void main(String[] args) {Integer i1 = Integer.valueOf(127);Integer i2 = Integer.valueOf(127);// i1 和 i2 是同一个对象,因为 127 在缓存范围内System.out.println(i1 == i2);  // 输出 trueInteger i3 = Integer.valueOf(128);Integer i4 = Integer.valueOf(128);// i3 和 i4 不是同一个对象,因为 128 不在缓存范围内System.out.println(i3 == i4);  // 输出 false}
}

Integer 缓存池通过共享 -128127 范围内的整数,减少了内存使用。

3.MyBatis 中的 SqlSessionFactory

MyBatis 是一个持久层框架,它通过享元模式优化了 SqlSessionFactory 对象的创建。SqlSessionFactory 是一个重量级对象,通常一个应用只需要一个实例。MyBatis 通过工厂模式和享元模式确保每个数据库只创建一个 SqlSessionFactory 实例,并重复使用。

享元模式的应用:

  • 内部状态SqlSessionFactory 对象(共享的连接配置)。
  • 外部状态:无(SqlSessionFactory 本身是不可变的)。

示例代码

public class MyBatisFlyweightExample {public static void main(String[] args) {SqlSessionFactory sessionFactory1 = MyBatisUtil.getSqlSessionFactory();SqlSessionFactory sessionFactory2 = MyBatisUtil.getSqlSessionFactory();// sessionFactory1 和 sessionFactory2 是同一个实例System.out.println(sessionFactory1 == sessionFactory2);  // 输出 true}
}

MyBatis 通过共享 SqlSessionFactory 实现了享元模式,避免重复创建数据库连接工厂,节省了系统资源。

4.Java 数据库连接池

在 Java 应用中,数据库连接池(如 HikariCP、DBCP 等)也是享元模式的经典应用。数据库连接是非常昂贵的资源,连接池通过共享有限的连接对象,避免重复创建和销毁连接,提升了系统性能。

享元模式的应用

  • 内部状态:连接池中的连接对象(可以共享)。
  • 外部状态:连接的具体使用状态(如连接是否空闲)。

代码概念

// 数据库连接池 Flyweight 模式
HikariDataSource dataSource = new HikariDataSource();
Connection conn1 = dataSource.getConnection();
Connection conn2 = dataSource.getConnection();// 使用同一个数据库连接池管理连接对象

数据库连接池通过享元模式复用连接对象,大大提高了数据库连接的性能和资源管理。

总结

  1. 减少内存消耗:通过共享相同对象,减少重复对象的创建,特别适合大量相似对象的场景。
  2. 提高系统性能:通过共享对象,减少内存使用,提升程序的运行效率。
  3. 增加系统复杂性:为了区分内部状态和外部状态,系统设计可能会更加复杂
  4. 适用场景有限:享元模式适用于存在大量相同或相似对象的场景,如果对象的状态不易共享,享元模式的效果有限。

使用场景

  1. 需要大量重复对象的场景:如图形绘制系统、文本编辑器中字符对象的管理。
  2. 缓存池:享元模式常用于对象池或缓存池中,避免创建大量相同的对象。
  3. 游戏开发:在游戏中,地图上的草地、树木等对象可以使用享元模式进行共享。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com