享元设计模式
一、享元设计模式
1、介绍
(1)享元模式(Flyweight Pattem)也叫蝇量模式:运用共享技术有效地支持大量细粒度的对象
(2)常用于系统底层开发,解决系统的性能问题。例如:数据库连接池,里面都是创建好的连接对象,在这些连接对象中有我们需要的则直接拿来用,避免重新创建,如果没有我们需要的,则创建一个
(3)享元模式能够解决重复对象的内存浪费问题,当系统中有大量相似对象,需要缓存池时,不需要总是创建新对象,可以充缓冲池里拿。这样可以降低系统内存,同时提高效率
(4)享元模式经典应用场景就是池技术了,String常量池、数据库连接池、缓冲池等等都是享元模式的应用,享元模式是池技术的重要实现方式
2、UML
Flyweight:抽象的享元角色,它是产品的抽象类,同时定义出对象的外部状态和内部状态的接口或实现
ConcreteFlyweight:具体的享元角色,是具体的产品类,实现抽象角色定义相关业务
UnsharedConcreteFlyweight:不可共享的角色,一般不会出现在享元工厂
Flyweight:享元工厂类,用于构建一个池容器(集合),同时提供从池中获取对象方法
内部状态和外部状态:
(1)享元模式提出两个要求:细粒度和共享对象。这里就涉及到内部状态和外部状态了,即将对象的信息分为两个部分:内部状态和外部状态
(2)内部状态指对象共享出来的信息,存储在享元对象内部且不会随环境的改变而改变(ConcreteFlyweight)
(3)外部状态指对象得以依赖的一个标记,是随环境改变而改变的,不可共享的状态(UnsharedConcreteFlyweight)
下方享元设计模式案例:内部状态为属性“type”,外部状态则为“user”
3、注意事项和细节
(1)享元模式,“享”表示共享,“元”表示对象
(2)系统中有大量对象,这些对象消耗大量内存,并且对象的状态大部分可以外部化是,考虑选用享元模式
(3)用唯一标识码判断,如果在内存中有,则返回这个唯一标识码所标识的对象,用HashMap/HashTable存储
(4)享元模式大大减少对象的创建,降低程序内存的占用,提高效率
(5)享元模式提高了系统的复杂度。需要分离出内部状态和外部状态,而内部状态具有固化特性,不会随着外部状态的改变而改变。
(6)使用享元模式,注意划分内部状态和外部状态,并且需要有一个工厂类加以控制
(7)享元模式经典的应用场景是需要缓存池的场景,例如:String常量池,数据库连接池
二、享元设计模式案例
1、介绍
- 抽象类“Article”为抽象的享元角色,内部定义了内部状态(属性type)和外部状态(对象User)
- 类“ConcreteArticle”为具体的享元角色,实现了抽象类“Article”
- 类“User”为不可共享的享元角色,会随着环境的变换而改变
- 类“ArticleFactory”是一个享元对象池,当需要对象时可以从享元对象池中获取,如果没有则创建一个并添加到池中
- 类“Client”为客户端,用于测试
2、UML
3、代码
/**
* @description: 文章
* @author: dashu
* @create: 17:33
*/
public abstract class Article {
/**
* 共享部分;内部状态
*
*
* <p>
* 文章发布的形式
*/
public String type;
public Article(String type){
this.type = type;
}
/**
* 阅读文章
* @param user 用户
*/
public abstract void browse(User user);
}
/**
* @description: 具体的文章
* @author: dashu
* @create: 17:34
*/
public class ConcreteArticle extends Article{
public ConcreteArticle(String type) {
super(type);
}
/**
* 阅读文章
* @param user 用户
*/
@Override
public void browse(User user) {
System.out.println("文章发布的形式为:" + type + ",阅读者:" + user.getName());
}
}
import java.util.HashMap;
/**
* @description: 文章工厂
* @author: dashu
* @create: 17:37
*/
public class ArticleFactory {
private HashMap<String, Article> pool;
public ArticleFactory() {
pool = new HashMap<String, Article>();
}
/**
* 根据文章发布的类型,返回一个文章,如果没有就创建一个文章,并放入到池中,并返回
* @param type
* @return
*/
public Article getArticle(String type){
if (!pool.containsKey(type)){
pool.put(type, new ConcreteArticle(type));
}
return pool.get(type);
}
/**
* 返回文章发布类型的总数(池中有多少个文章发布类型)
* @return
*/
public int getArticleCount(){
return pool.size();
}
}
/**
* @description: 用户
* @author: dashu
* @create: 12:58
*/
public 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;
}
}
/**
* @description: 客户端
* @author: dashu
* @create: 12:58
*/
public class Client {
public static void main(String[] args) {
ArticleFactory articleFactory = new ArticleFactory();
Article gzh = articleFactory.getArticle("公众号");
gzh.browse(new User("tom"));
Article bk = articleFactory.getArticle("博客");
bk.browse(new User("jek"));
}
}