alexpdh's blog

Java设计模式(二十三):享元模式

享元模式(Flyweight Pattern)

享元模式(Flyweight Pattern):属于对象的结构模式。运用共享技术有效地支持大量细粒度的对象。


享元模式UML图

flyweight-pattern.jpg


享元模式涉及的角色

抽象享元(Flyweight)角色:所有有具体享元类的超类或接口,通过这个接口,Flyweight 可以接受并作用于外部状态。
具体享元(ConcreteFlyweight)角色:实现抽象享元角色所规定出的接口。如果有内部状态时,为内部状态提供存储空间。
未共享的具体享元(UnShargedFlyweight)角色:指那些不需要共享的 Flyweight 子类,因为 Flyweight抽象类共享成为可能,但它并不强制共享。
享元工厂(FlyweightFactory)角色:一个享元工厂,用来创建并管理 Flyweight 对象,它主要是用来确保合理地共享 Flyweight,当用户请求一个 Flyweight 时,FlyweightFactory 对象听歌一个已创建的实例或者创建一个(如果不存在的话)。


示例代码

抽象享元类 Flyweight

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.example.flyweightPattern;
/**
* 享元模式:抽象享元类
*
* @author pengdh
* @date: 2017-08-13 17:09
*/
public abstract class Flyweight {
/**
* 外部状态作为参数传入方法中,
* 改变了方法的行为,但是并不改变对象的内部状态
* @param extrinsicstate 外部状态
*/
public abstract void operation(int extrinsicstate);
}

具体享元类 ConcreteFlyweight

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package com.example.flyweightPattern;
/**
* 享元模式:具体享元类
*
* @author pengdh
* @date: 2017-08-13 17:12
*/
public class ConcreteFlyweight extends Flyweight {
/**
* 持有一个内部状态
*/
private String intrinsicstate;
/**
* 构造函数,内部状态作为参数传入
* @param intrinsicstate
*/
public ConcreteFlyweight(String intrinsicstate) {
this.intrinsicstate = intrinsicstate;
}
/**
* 外部状态作为参数传入方法中,
* 改变了方法的行为,但是并不改变对象的内部状态
* @param extrinsicstate 外部状态
*/
@Override
public void operation(int extrinsicstate) {
System.out.println("Intrinsic State:" + intrinsicstate);
System.out.println("Extrinsic State:" + extrinsicstate);
}
}

非共享具体享元类 UnSharedConcreteFlyweiht

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.example.flyweightPattern;
/**
* 享元模式:非共享具体享元类
*
* @author pengdh
* @date: 2017-08-13 17:15
*/
public class UnSharedConcreteFlyweiht extends Flyweight {
@Override
public void operation(int extrinsicstate) {
System.out.println("非共享的具体 Flyweiht:" + extrinsicstate);
}
}

享元工厂类 FlyweihtFactory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.example.flyweightPattern;
import java.util.HashMap;
import java.util.Map;
/**
* 享元模式:享元工厂类
*
* @author pengdh
* @date: 2017-08-13 17:17
*/
public class FlyweihtFactory {
private Map<String, Flyweight> map = new HashMap<String, Flyweight>();
public Flyweight create(String intrinsicstate) {
if (!map.containsKey(intrinsicstate)) {
map.put(intrinsicstate, new ConcreteFlyweight(intrinsicstate));
}
return map.get(intrinsicstate);
}
}

客户端测试类 FlyweightPatternTest

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.example.flyweightPattern;
/**
* 享元模式:客户端测试类
*
* @author pengdh
* @date: 2017-08-13 17:24
*/
public class FlyweightPatternTest {
public static void main(String[] args) {
int extrinsicstate = 22;
FlyweihtFactory factory = new FlyweihtFactory();
Flyweight f1 = factory.create("X");
f1.operation(21);
Flyweight f2 = factory.create("Y");
f2.operation(20);
Flyweight f3 = factory.create("X");
f3.operation(19);
boolean flag = false;
if (f1 == f3) {
flag = true;
}
System.out.println("内部状态是否可以共享:" + flag);
Flyweight uf1 = new UnSharedConcreteFlyweiht();
uf1.operation(18);
}
}

享元模式使用场景

一个系统有大量相同或者相似的对象,由于这类对象的大量使用,造成内存的大量耗费时可以考虑使用;对象的大部分状态都可以外部化,可以将这些外部状态传入对象中;使用享元模式需要维护一个存储享元对象的享元池,而这需要耗费资源,因此,应当在多次重复使用享元对象时才值得使用享元模式。


享元模式优点

  • 它可以极大减少内存中对象的数量,使得相同对象或相似对象在内存中只保存一份。
  • 享元模式的外部状态相对独立,而且不会影响其内部状态,从而使得享元对象可以在不同的环境中被共享。

享元模式缺点

  • 享元模式使得系统更加复杂,需要分离出内部状态和外部状态,这使得程序的逻辑复杂化。
  • 为了使对象可以共享,享元模式需要将享元对象的状态外部化,而读取外部状态使得运行时间变长。

参考文献

alexpdh wechat
欢迎扫一扫关注 程序猿pdh 公众号!