-
Notifications
You must be signed in to change notification settings - Fork 0
享元模式
ZHI-XINHUA edited this page Jan 11, 2019
·
1 revision
享元模式是对象的结构模式,以共享的方式高效地支持大量的细粒度对象。
享元对象分内蕴状态和外蕴状态,外蕴状态不可以影响享元对象的内蕴状态,它们是相互独立的:
- 内蕴状态:一个内蕴状态是存储在享元对象内部的,并且是不会随环境改变而有所不同的。因此,一个享元可以具有内蕴状态并可以共享。
- 外蕴状态:一个外蕴状态是随着环境改变而 改变、不可以共享的状态。享元对象的外蕴状态必须是由客户端保存,并在享元对象被创建之后,需要使用的时候再传入到享元对象内部。
- 抽象享元角色(Flyweight):是多有具体享元类的超类,为这些类规定需要实现的公共接口。那些需要外蕴状态的操作可以通过调用方法以参数形式传入。
- 享元工厂角色(FlyweightFactory):负责创建和管理享元角色。本角色必须保证享元对象可以被系统适当地共享。当一个客户端对象调用 一个享元对象的时候,享元工厂角色会检查系统中是否已经有一个复合要求的享元对象。如果已有,享元工厂角色就应当提供这个已有 的享元对象;如果没有,就创建一个合适的享元对象。
- 具体享元角色(ConcreteFlyweight):实现抽象享元角色所规定的接口。如果有内蕴状态的话,必须负责为内蕴状态提供存储空间。享元对象的内蕴状态必须与 对象所处的环境无关,从而使得享元对象可以在系统内共享的。
- 客户端角色(Client):本角色需要维护一个对所有享元对象的引用。本角色需要自行存储所有共享对象的外蕴状态。
uml:
(1)Flyweight 抽象享元角色
/**
* 抽象享元角色(Flyweight):是多有具体享元类的超类,为这些类规定需要实现的公共接口。那些需要外蕴状态的操作可以通过调用方法以参数形式传入
*/
public abstract class Flyweight {
/**
* 一个示意的方法,参数outState是外蕴状态
* @param outState
*/
abstract public void operation(String outState);
}
(2)ConcreteFlyweight具体享元角色
/**
* 具体享元角色(ConcreteFlyweight):实现抽象享元角色所规定的接口。如果有内蕴状态的话,必须负责为内蕴状态提供存储空间。享元对象的内蕴状态必须与
* 对象所处的环境无关,从而使得享元对象可以在系统内共享的。
*/
public class ConcreteFlyweight extends Flyweight {
//为内蕴状态提供存储空间
private String innerState;
/**
* 构造器,内蕴状态作为参数传入
* @param innerState
*/
public ConcreteFlyweight(String innerState){
this.innerState = innerState;
}
/**
* 外蕴状态作为参数传入方法中,改变方法的行为,但是不改变对象的内蕴状态
* @param outState
*/
@Override
public void operation(String outState) {
System.out.println("对象:"+this+" 内蕴状态innerState:"+innerState+" 外蕴状态outState:"+outState);
}
}
(3)FlyweightFactory 享元工厂角色:负责创建和管理享元角色
/**
* 享元工厂角色(FlyweightFactory):负责创建和管理享元角色。本角色必须保证享元对象可以被系统适当地共享。当一个客户端对象调用
* 一个享元对象的时候,享元工厂角色会检查系统中是否已经有一个复合要求的享元对象。如果已有,享元工厂角色就应当提供这个已有
* 的享元对象;如果没有,就创建一个合适的享元对象
*/
public class FlyweightFactory {
private Map<String,Flyweight> map = new HashMap<String,Flyweight>();
public FlyweightFactory(){
}
/**
* 必须指出的是,客户端不可以直接将具体享元类实例化,而必须通过一个工厂对象利用一个
* factory()方法得到享元对象。一般而言,享元工厂对象在整个系统中只有一个,隐藏可以是单例模式。
* @param innerState
* @return
*/
public Flyweight factory(String innerState){
if(map.containsKey(innerState)){
return map.get(innerState);
}
Flyweight flyweight = new ConcreteFlyweight(innerState);
map.put(innerState,flyweight);
return flyweight;
}
}
(4)客户端角色(Client):本角色需要维护一个对所有享元对象的引用
/**
* Created by xh.zhi on 2018-11-6.
* 客户端角色(Client):本角色需要维护一个对所有享元对象的引用。本角色需要自行存储所有共享对象的外蕴状态。
*/
public class Client {
public static void main(String[] args) {
//创建一个享元工厂对象
FlyweightFactory factory = new FlyweightFactory();
//向享元工厂对象请求一个内蕴状态为a的享元对象
Flyweight fly = factory.factory("a");
//已参数方式传入一个外蕴状态
fly.operation("hello");
Flyweight fly1 = factory.factory("a");
//已参数方式传入一个外蕴状态
fly1.operation("world");
}
}
- 享元模式由于其共享的特性,可以在任何“池”中操作,比如:线程池、数据库连接池。
- String类 ,String对象是不可变对象,一旦创建出来就不能改变,如果需要改变一个字符串的值,就只好创建一个新的String对象。在JVM内部,String 对象是共享的。如果系统中有两个String对象所包含的字符串相同的话,JVM实际上只创建一个String对象提供给两个引用,从而实现String对象的共享。String的
intern()
方法给出这个字符串再共享池中的唯一实例。
时间换空间。
优点:
- 极大减少内存中对象的数量
- 相同或相似对象内存中只存一份,极大的节约资源,提高系统性能
- 外部状态相对独立,不影响内部状态
缺点:
- 模式较复杂,使程序逻辑复杂化
- 为了节省内存,共享了内部状态,分离出外部状态,而读取外部状态使运行时间变长。用时间换取了空间。
设计模式