读完这篇文章,深受启发,可以先参考,https://www.cnblogs.com/lixin-link/p/11104658.html
1、简介
享元(Flyweight)模式的定义:运用共享技术来有効地支持大量细粒度对象的复用。它通过共享已经存在的又橡来大幅度减少需要创建的对象数量、避免大量相似类的开销,从而提高系统资源的利用率。
角色组成:
- 抽象享元(Flyweight)角色 :父接口,以规定出所有具体享元角色需要实现的方法。
- 具体享元(ConcreteFlyweight)角色:实现抽象享元角色所规定出的接口。
- 享元工厂(FlyweightFactory)角色 :本角色负责创建和管理享元角色。本角色必须保证享元对象可以被系统适当地共享。当一个客户端对象调用一个享元对象的时候,享元工厂角色会检查系统中是否已经有一个符合要求的享元对象。如果已经有了,享元工厂角色就应当提供这个已有的享元对象;如果系统中没有一个适当的享元对象的话,享元工厂角色就应当创建一个合适的享元对象。
享元模式中有两个概念:
内部状态:在享元对象内部不随外界环境改变而改变的共享部分。
外部状态:随着环境的改变而改变,不能够共享的状态就是外部状态。
- 由于享元模式区分了内部状态和外部状态,所以我们可以通过设置不同的外部状态使得相同的对象可以具备一些不同的特性,而内部状态设置为相同部分。在我们的程序设计过程中,我们可能会需要大量的细粒度对象来表示对象,如果这些对象除了几个参数不同外其他部分都相同,这个时候我们就可以利用享元模式来大大减少应用程序当中的对象。
2、具体实现
以图书馆借书为例:
//抽象享元角色
interface Book{
public void borrow();
}
//具体享元角色
class ConcreteBook implements Book{
private String name;
public ConcreteBook(String name){
this.name = name;
}
@Override
public void borrow() {
System.out.println("图书馆借出一本书,书名为:"+this.name);
}
}
//享元工厂类,管理具体享元角色
class Library{
//建立一个共享对象的容器
private Map<String,Book> cache = new HashMap<String,Book>();
//对工厂进行单例
private static Library lib = new Library();
public static Library getInstance(){
return lib;
}
//管理共享角色,如果容器里有,就直接返回,没有则创建一个,并放入容器
public Book toBrrow(String bookName){
Book book = null;
if(cache.containsKey(bookName)) {
book = this.cache.get(bookName);
}else{
book = new ConcreteBook(bookName) ;
this.cache.put(bookName,book);
}
return book;
}
public int getNum(){
return cache.size();
}
}
class borrower{
public static List list = new ArrayList();
public static void main(String[] args) {
Library factroy = Library.getInstance();
list.add(factroy.toBrrow("java设计模式详解"));
list.add(factroy.toBrrow("Head First"));
list.add(factroy.toBrrow("深入理解java虚拟机"));
list.add(factroy.toBrrow("java设计模式详解"));
list.add(factroy.toBrrow("java编程思想"));
System.out.println("当前图书馆借出去" + list.size() +"本书");
System.out.println("当前图书馆库存"+factroy.getNum()+"本书");
}
}
当前图书馆借出去5本书
当前图书馆库存4本书
上面例子中,书籍Book就是细粒度的对象,我们通过享元模式,来减少需要创建的对象的数量,减少系统开销。java中String字符串常量池就是这种方式,创建一个字符串对象的时候,会先去常量池中查找,如果有则直接返回引用。
3、总结
优点:享元模式的优点最主要的是极大的减少了系统中对象的创建,降低了内存使用提高了效率。
缺点:为了使一些对象共享,对对象区分了内在状态和外在状态,使系统逻辑变为复杂了,使系统更加难于理解了。
应用场景:
1、系统需要大量相似对象
2、创建这些对象需要花费大量资源
3、状态可分为内在状态和外在状态,可以根据内在状态分为各种组。
4、需要缓冲池的场景
4、扩展
前面学习了单例模式,原型模式,还有这次的享元模式,总感觉这几种模式都差不多,都是为了减少对象的创建,这里做一下区分。
-
原型模式:使用原型实例指定创建对象的种类,然后通过拷贝这些原型来创建新的对象。
-
单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
-
享元模式:运用共享技术有效地支持大量细粒度的对象。
原型模式——享元模式
- 原型模式是通过原型实例指定创建对象。达到类的复用。通过深浅拷贝类来实现复用以节约资源开销。再看享元模式抽出相似的一些对象,定义其内在状态和外在状态来达到对象共享。运用共享的技术来支持大量细粒度的对象。也就是前面更倾向于实现复用,而享元模式更加倾向于共享使用。所以也不适合放一起进行比较的。
单例模式——享元模式
- 单例例模式保证的是类仅有一个实例,然后提供一个全局访问点,所有访问都可以访问得到。达到的是一个实例数据的共享。我们再看享元模式,享元模式通过的是将相似的对象进行共享,然后控制内在状态和外在状态来达到变化。享元模式是对象级别的,也就是实现的是多个对象——对象池。而单例模式是一类一个对象的实例。享元模式更加注重的是节约内存空间,提高其性能。然而单例模式注重的是数据的共享。