享元模式
大话设计模式上举得是大量的私人项目,这点很是羡慕,没有私人项目的经验所以只能干瞪眼了喽。
享元模式实现相同或者相似对象的重用。也就是说实现相同或者相似对象的代码共享。
享元模式(Flyweight):运用共享技术有效地支持大量细粒度的对象。
套用大话设计模式的一段话就是:
享元模式可以避免大量非常相似类的开销。
在程序设计中,有时需要生成大量细粒度的类实例来表示数据。
如果能发现这些实例除了几个参数外基本相同,有时就能够大幅度地减少需要实例化的类的数量。
如果能把那些参数移到类实例的外面,在方法调用时将他们传递进来,就可以通过共享大幅度地减少单个实例的数目。
从几个参数外基本相同这句话不难看出,享元模式所需的状态有两部分,分别是相同的内部和不同的外部。
这里出现了几个名词,首先我们来举个栗子说明下粒度的问题:
就比如说车,大家都知道公路上的车颜色有很多种,但是他们都是车,在这里就可以认为是粗粒度的,而颜色这些就可以认为是细粒度的。
然后就是内外部状态:
内部状态就是共享的部分也就是相同的部分。
外部状态就是随着坏境改变的部分
现在来看下享元模式组成:
抽象享元类(Flyweight):所有具体享元类的超类或者接口,通过这个接口,Flyweight可以接受并作用于外部专题
具体享元类(ConcreteFlyweight):指定内部状态,为内部状态增加存储空间。
非共享具体享元类(UnsharedConcreteFlyweight):指出那些不需要共享的Flyweight子类。
享元工厂类(FlyweightFactory):用来创建并管理Flyweight对象,它主要用来确保合理地共享Flyweight,当用户请求一个Flyweight时,FlyweightFactory就会提供一个已经创建的Flyweight对象或者新建一个(如果不存在)。
享元模式最重要的就是享元工厂类了,它是维护实例的。
当实例不存在时,就创建一个放入享元池。
当实例存在,就直接从享元池中取出实例来用。
这个跟java中String的工作方式一样,下面代码他们输出的是true因为指向的是同一个地址:
String one="享元模式";
String two="享元模式";
System.out.println(one == two);
同样的在给String赋值的时候会在内存中去查找是否存在此对象,如果不存在则创建然后指向这个地址,如果存在直接指向。
下面我们来看一下享元模式的UML图
在就是上面案例的代码实现:
//抽象享元类,例子是车
interface Car{
void getCar();
}
//具体享元类,例子是跑车
class Roadster implements Car{
private String color;
public Roadster(String color){
this.color=color;
}
@Override
public void getCar() {
System.out.println("获得一辆"+color+"跑车");
}
}
//享元工厂类
class CarFactory{
public static Map map=new HashMap();
public static Car getACar(String color){
//判断有无同颜色的车
if(!map.containsKey(color)){
map.put(color, new Roadster(color));
}
return (Car)map.get(color);
}
public static int getKind(){
return map.size();
}
}
public class Client {
public static void main(String[] args) {
Car car1=CarFactory.getACar("黄色");
car1.getCar();
Car car2=CarFactory.getACar("黄色");
car2.getCar();
Car car3=CarFactory.getACar("蓝色");
car3.getCar();
Car car4=CarFactory.getACar("红色");
car4.getCar();
System.out.println("一共获得"+CarFactory.getKind()+"种颜色跑车");
}
}
输出是
获得一辆黄色跑车
获得一辆黄色跑车
获得一辆蓝色跑车
获得一辆红色跑车
一共获得3种颜色跑车
很明显可以看出,不用创建很多实例了。
享元模式的优点是:
可以减少很多相似对象,减少系统的内存消耗。
使用了内外部的模式且相对的比较独立,所以享元对象能够在不同的坏境中被共享。
至于适用范围,不说也很清楚啦,只要能发挥它优势的地方都可以使用,也就是说一个系统中存在大量相似或相同对象的时候就可以使用了。