1.今天这篇享元模式学习的时间比之前几个模式都长,看了好几篇他人的博客,最后用自己最简洁直白的话总结出来这篇文章。
2.为什么我们要使用享元模式? 顾名思义,享元,就是共享一个"元",
例如,我们打一篇英文的文章,大概200字,1000多个字母,我们并不需要创建1000个字母的对象,
实际上我们由始至终只是在做一个26个字母的组合,我们仅创建了26个字母就完成的一篇文章,
当我第一次敲下a后,后台(姑且叫做后台吧)会创建并存下了一个a,
下一次我再需要使用a时,不需要再次创建一个a对象,只要从后台调用之前创建并存下的a。
这就是享元模式——重复多次用到同一个元素,为了节省内存,那就共享!
FlyweightFactory(工厂类):从里面获取需要的元素
Flyweight(享元抽象类): 不同类型的需共享的元素都是它的子类
ConcreteFlyweight,unsharedConcreteFlyweight(具体类): 具体的共享对象
3.例子:假设我在写一封email,里面需要重复用到 不同颜色的字 和 不同大小的字 ,现在模拟这个过程。
Flyweight,例子中用到的颜色,字体小大都是它的子类/具体实现类
package pers.reus.model.flyweight;
/* *
* Flyweight,享元模式的抽象类,当A类继承Flyweight类
* 代表A类有可能是一个需要被重复使用多次的类
* 所有A类才使用了享元模式
* */
public abstract class Flyweight {
public abstract void show();
}
Color 颜色类,通过它来设定字体颜色
package pers.reus.model.concreteFlyweight;
import pers.reus.model.flyweight.Flyweight;
//Color是Flyweight的concrete类
public class Color extends Flyweight{
String color;
//Color的构造函数需传入一个参数
public Color(String color){
this.color = color;
}
//展示这个Color类中被赋予的颜色
public void show() {
System.out.print("颜色: " + color);
}
}
Font,字体大小类
package pers.reus.model.concreteFlyweight;
import pers.reus.model.flyweight.Flyweight;
//Font类是Flyweight的concrete类
public class Font extends Flyweight{
String font;
//Font的构造函数需传入一个参数
public Font(String font){
this.font = font;
}
//展示这个Font类中被赋予的字体大小值
public void show() {
System.out.println(" 字体大小: " + font);
}
}
FlyweightFactory,工厂类,我们需要的 字体颜色 和 字体大小 都是从工厂类中获取,如果工厂类里面的hashtable没有存到有我们需要的,就会新建一个Color和Font对象来满足我们的需求,而下一次我们再有同样的请求的时候,hashtable就会有我们需要求 字体颜色 或 字体大小,不需要再重新新建对象。
package pers.reus.model.flyweightFactory;
import java.util.Hashtable;
import pers.reus.model.concreteFlyweight.Color;
import pers.reus.model.concreteFlyweight.Font;
import pers.reus.model.flyweight.Flyweight;
//FlyweightFactory享元模式工厂类
public class FlyweightFactory {
//创建2个Hashtable分别用来存储 颜色 和 字体大小
private Hashtable colorFlyweights = new Hashtable();
private Hashtable fontFlyweights = new Hashtable();
/* *
* getColorFlyweight作用是
* 当接收一个object对象
* 就会从color的hashtable里面找有没有这个对象
* 如果有就调用,没有就new Color()
* */
public Flyweight getColorFlyweight(Object str) {
//当接收一个值,先看看hashtable里面有没有
Flyweight flyweight = (Flyweight) colorFlyweights.get(str);
//if 没有
if(flyweight == null){
//新建一个Color对象,并赋予它刚刚接收的值
flyweight = new Color((String)str);
//把新的Color对象存到hashtable里面
colorFlyweights.put(str, flyweight);
}
return flyweight;
}
/* *
* getFontFlyweight作用是雷同的
* 为什么参数是Object str
* 因为Hashtable里面的参数是Object
* */
public Flyweight getFontFlyweight(Object str) {
//以下的步骤和上面是一样的,做两个函数只是为了说明享元模式的扩展性
Flyweight flyweight = (Flyweight) fontFlyweights.get(str);
if(flyweight == null){
flyweight = new Font((String)str);
fontFlyweights.put(str, flyweight);
}
return flyweight;
}
//返回两个Hashtable的长度
public int getColorFlyweightSize(){
return colorFlyweights.size();
}
public int getFontFlyweightSize(){
return fontFlyweights.size();
}
}
Client类的测试:
package pers.reus.model.client;
import pers.reus.model.flyweight.Flyweight;
import pers.reus.model.flyweightFactory.FlyweightFactory;
public class FlyweightPatternClient {
public static void main(String[] args) {
//创建工厂
FlyweightFactory factory = new FlyweightFactory();
//c1~5表示5个颜色对象,f1~5表示5个字体对象
Flyweight c1,c2,c3,c4,c5;
Flyweight f1,f2,f3,f4,f5;
//5次获取颜色对象
c1 = factory.getColorFlyweight("蓝色");
c2 = factory.getColorFlyweight("白色");
c3 = factory.getColorFlyweight("绿色");
c4 = factory.getColorFlyweight("白色");
c5 = factory.getColorFlyweight("蓝色");
//5次获取字体对象
f1 = factory.getFontFlyweight("8px");
f2 = factory.getFontFlyweight("18px");
f3 = factory.getFontFlyweight("18px");
f4 = factory.getFontFlyweight("8px");
f5 = factory.getFontFlyweight("8px");
//展示
c1.show();
f1.show();
c2.show();
f2.show();
c3.show();
f3.show();
c4.show();
f4.show();
c5.show();
f5.show();
//显示颜色和字体一共创建了几个对象
System.out.println("创建了 " + factory.getColorFlyweightSize() + " 个颜色对象");
System.out.println("创建了 " + factory.getFontFlyweightSize() + " 个字体对象");
}
}
测试结果: 可以看见分别向工厂类请求了5次字体颜色 和 5次字体小大,但是最后返回显示只创建了3个Color类,2个Font类,因为 "蓝白绿白蓝" 中,3个”蓝“享元一个Color类,Font也是同样的道理,Font的功能只是为了说明享元模式的易扩展性,可以扩展多个可共享的功能。
颜色: 蓝色 字体大小: 8px
颜色: 白色 字体大小: 18px
颜色: 绿色 字体大小: 18px
颜色: 白色 字体大小: 8px
颜色: 蓝色 字体大小: 8px
创建了 3 个颜色对象
创建了 2 个字体对象
上几篇文章一直没说明:写博客是一个很好的检验过程,有些模式看着觉得懂了,但是实战时候却经常丢三落四地忘记小细节,而博客上也是用自己的语言去记录学习过程,可能有些自己能会心的字段别人却看不懂,希望大家多多支出,我是一只技术菜鸟,却有一颗成为大牛的心。