一、享元模式介绍
享元模式(Flyweight Pattern)也叫蝇量模式,主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。
它常用与系统底层的开发,解决系统地性能问题。像数据库连接池,里面都是创建好的连接对象,在这些连接中有我们需要的则直接拿来用,避免重新创建,如果没有我们需要的,则创建一个。
享元模式角色:
FlyWeight
:是抽象的享元角色,它是产品抽象类,定义出对象的外部状态和内部状态。
- 内部状态:存储在享元对象内部且不会随环境改变而改变。
- 外部状态:对象得以依赖的一个标记,是随环境改变而改变、不可共享的状态。
ConcreteFlyWeight
:是具体的享元角色,实现抽象角色定义相关业务。UnSharedConcreteFlyWeight
:是不可共享的角色,一般不会出现在享元工厂。FlyWeightFactory
:享元工厂类,用于构建一个池容器(集合),同时提供从池中获取对象方法。此处我们有一个诉求:
- 发布一个小型网站,不同客户希望以不同方式进行发布(包括但不限于微博、博客、新闻等形式)。
- 传统实现方式:直接复制粘贴后根据客户需求再进行定制修改。
- 传统方式会带来的问题:网站结构相似度很高,都不是高访问量网站,若通过此方式会造成服务器资源浪费。
- 解决思路:采用享元模式(整合至一个网站,共享其相关的代码和数据,对于硬盘、内存、CPU、数据库空间等服务器资源都可以达成共享,更加节省资源的情况下,也利于维护和拓展。)
二、享元模式使用
2.1 示例关系:
2.2 代码实现:
/* *
* 1. 外部状态:用户类。
*/
class User {
private String name;
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
/* *
* 2. 抽象享元角色:网站类。
*/
abstract class WebSite {
public abstract void use(User user);
}
/* *
* 3. 具体享元角色:具体网站类。
*/
class ConcreteWebSite extends WebSite {
/* *
* 内部状态:网站发布形式。
*/
private String type;
public ConcreteWebSite(String type) {
this.type = type;
}
@Override
public void use(User user) {
System.out.println("网站发布形式是 :" + this.type +
",用户" + user.getName() + "正在使用网站...");
}
}
/* *
* 4. 享元工厂:控制内部状态。
*/
class WebSiteFactory {
private Map<String, ConcreteWebSite> pool = new HashMap<>(8);
/* *
* 获取网站类型。
*/
public WebSite getWebSiteCategory(String type) {
// 如果没有该网站发布类型,就在池中创建一个。
if (!pool.containsKey(type)) {
pool.put(type, new ConcreteWebSite(type));
}
return pool.get(type);
}
/* *
* 获取网站发布种类(当前池的大小)。
*/
public int getWebSiteCount() {
return this.pool.size();
}
}
/* *
* 客户端调用。
*/
public class Client {
public static void main(String[] args) {
WebSiteFactory factory = new WebSiteFactory();
factory.getWebSiteCategory("微博").use(new User("tom"));
factory.getWebSiteCategory("微博").use(new User("jack"));
factory.getWebSiteCategory("知乎").use(new User("lucas"));
factory.getWebSiteCategory("微信公众号").use(new User("jan"));
System.out.println("当前网站分类共有" + factory.getWebSiteCount() + "种。");
// 网站发布形式是 :微博,用户tom正在使用网站...
// 网站发布形式是 :微博,用户jack正在使用网站...
// 网站发布形式是 :知乎,用户lucas正在使用网站...
// 网站发布形式是 :微信公众号,用户jan正在使用网站...
// 当前网站分类共有3种。
}
}
三、享元模式总结
优点:
- 大大减少了对象的创建,降低了程序内存的占用,提升了效率。
缺点:
- 提高了系统的复杂度,需要分离出内部状态和外部状态。一般外部状态具有固化特性,不应该随着内部状态改变而改变,这是使用享元模式需要注意的地方。
应用场景:
- 当系统中有大量对象消耗掉大量内存,并且这些对象的状态大部分可以外部化时,就可以考虑从使用该模式。
String
常量池、数据库连接池、缓冲池等等都是享元模式的应用,该模式是“池技术
”的重要实现方式。JDK
中Integer
类。
四、结束语
“-------怕什么真理无穷,进一寸有一寸的欢喜。”
微信公众号搜索:饺子泡牛奶。