(十三)享元模式(Flyweight)
最后更新于:2022-04-01 15:48:32
享元模式(Flyweight)就是把部分和整体的关系用树形结构来表示,从而使客户端能够把一个个的部分对象和有他们组合起来的整体对象采用同样的方式看待,他也是一个继承的替代,其实具体的说,享元模式就是用时间交换了空间。用程序的运行速度来读取是否重复的对象内容,然后不创建一个重复的对象来节省空间,于此同时就大大提高了程序的运行效率。
下面就简单的原理图:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-07-12_57845609ab493.png)
然后通过一个字符的库创建简单的理解了一下享元模式,我们要创建一个字符库,这样就避免不了一些字符使我们想重复用的,这样如果我们每次用都重新的创建一个对象,然后分配空间,那么对于好多重复的字符会明显的浪费空间,这个时候就引入了享元模式。
首先创建一个字符的接口,定义了一个负责拿到所在实例中的字符的方法getName();如下:
~~~
package coml.designpattern.flyweight;
public interface Characters {
public String getName();
}
~~~
紧接着定义了一个公用的子类实现了这个接口,书中是做了N个子类实现,这里我就用了一个子类,并在Flyweight种也有区别,个人觉得这样减少了代码的复用:
~~~
package coml.designpattern.flyweight;
public class Character implements Characters {
private String name;
public Character(String name) {
this.name = name;
}
@Override
public String getName() {
// TODO Auto-generated method stub
return this.name;
}
}
~~~
然后在Flyweight中定义创建字符的具体的方法和相关的逻辑:
~~~
package coml.designpattern.flyweight;
import java.util.ArrayList;
import java.util.List;
public class Flyweight {
private List list = new ArrayList();
public Characters getCharacter(String name) {
Characters characters = null;
for (int i = 0; i < list.size(); i++) {
characters = (Characters) list.get(i);
if (name.equals(characters.getName())) {
System.out.println(name + "不是第一次使用,未分配空间");
break;
} else {
characters = null;
}
}
if (characters == null) {
characters = new Character(name);
System.out.println(name + "第一次使用,并分配空间");
list.add(characters);
}
return characters;
}
}
~~~
定义了一个list,每次有新对象的时候就放进去,然后每次调用GetCharacter时候都会去遍历整个list想要的对象有没有创建好,如果有就不再创建,如果没有在创建,书中这里是用了N个Characters的实现类,在if语句块里面定义了N中情况,每一个字符就是一个对象,我这里就一个实现类,然后用不同的引用而已, 其实效果是一样的,然后客户端的调用:
~~~
package coml.designpattern.flyweight;
public class Client {
public static void main(String[] args) {
Flyweight flyweight = new Flyweight();
Characters study1 = flyweight.getCharacter("study");
Characters pattern = flyweight.getCharacter("pattern");
Characters study2 = flyweight.getCharacter("study");
Characters java = flyweight.getCharacter("java");
Characters study3 = flyweight.getCharacter("study");
Characters js = flyweight.getCharacter("js");
System.out.println(study1.getName() + "\t" + java.getName() + "\t"
+ study2.getName() + "\t" + pattern.getName() + "\t"
+ study3.getName() + "\t" + js.getName() + "\t");
}
}
~~~
输出结果:
~~~
study第一次使用,并分配空间
pattern第一次使用,并分配空间
study不是第一次使用,未分配空间
java第一次使用,并分配空间
study不是第一次使用,未分配空间
js第一次使用,并分配空间
study java study pattern study js
~~~
这样发现study虽然使用了三次但是他只创建了一次,如果使用N次,那么会很明显的减少了空间的使用;
在数据库连接池就是实际中的应用,先创建好一个池,每次有人要取得数据不会再像JDBC一样创建一个新的连接,这样减少了服务器端的压力,提高了项目的性能;
使用享元模式可以大大节省空间,但是需要维护所有的享元对象,如果 要维护的享元很多,在查找的时候要消耗大量的时间,因此享元模式是典型的以时间来交换空间。