模式导读:
世上没有相同的两片叶子,尽管它们可能非常相似,无论是颜色,大小亦或是重量等等,也会有不同之处,比如纹理,厚度等等。当我们需要将两片叶子用语言描述出来时,你是会选择两者分开描述,从颜色到厚度,从抽象到具体等等还是会选择两者同时描述,将共同点抽取出来然后细话两者不同。显然后者相比于前者既省时间又提高了辨识度,效率明显提升。享元模式在生活中随处可见,抽取相同属性放入一个容器以便共享,并且可以保证该属性不会随外部环境变化而发生变化。这便是享元模式。
核心:
享元模式以共享的方式高效的支持大量细粒度对象的重用。
享元对象能做到共享的关键是区分了内部状态和外部状态。
内部状态:可以共享,不会随环境变化而变化。
外部状态:不可以共享,会随环境变化而变化。
参考类图:
FlyweightFactory(享元工厂类):创建并管理享元对象,享元池一般设计成键值对。
FlyWeight(抽象享元类):通常是一个接口或抽象类,声明公共方法,这些方法可以向外界提供对象的内部状态,设置外部状态。
ConcretFlyWeight(具体享元类):为内部状态提供成员变量进行存储。
UnsharedConcreteFlyWeight(非共享享元类):不能被共享的子类可以设计为非共享享元类。
代码实现:
1.抽象享元类
1 package com.etc;
2 //抽象享元类 ->内存卡
3 public interface AbstractMemoryCard {
4 //内存卡的颜色获取
5 String getColor();
6 void setColor(String c);
7 void showMessage(ExternalState state);
8 }
2.具体享元类
1 package com.etc;
2 //具体的享元类
3 public class MemoryCard implements AbstractMemoryCard {
4
5 private String color;
6
7 //构造器
8 public MemoryCard(String color) {
9 super();
10 this.color = color;
11 }
12
13 @Override
14 public String getColor() {
15 return color;
16 }
17
18 @Override
19 public void setColor(String color) {
20 this.color=color;
21 }
22
23 @Override
24 public void showMessage(ExternalState state) {
25 System.out.println("******内存卡信息:*******");
26 System.out.println("*颜色:"+color);
27 System.out.println("*品牌:"+state.getBrand());
28 System.out.println("*内存大小:"+state.getStoreSize()+"g");
29 System.out.println("*********************");
30 }
31
32 }
3.非共享享元类
1 package com.etc;
2 //非共享享元类(外部状态类)->包含内存卡的内存大小,以及相应的品牌
3 public class ExternalState {
4
5 private int storeSize;
6 private String brand;
7
8 public ExternalState(int storeSize, String brand) {
9 super();
10 this.storeSize = storeSize;
11 this.brand = brand;
12 }
13 public int getStoreSize() {
14 return storeSize;
15 }
16 public void setStoreSize(int storeSize) {
17 this.storeSize = storeSize;
18 }
19 public String getBrand() {
20 return brand;
21 }
22 public void setBrand(String brand) {
23 this.brand = brand;
24 }
25
26
27 }
4.享元工厂
1 package com.etc;
2
3 import java.util.HashMap;
4 import java.util.Map;
5
6 //享元工厂类
7 public class Factory {
8 //建立享元池
9 private static Map<String,AbstractMemoryCard> map=new HashMap<String,AbstractMemoryCard>();
10 //通过内存卡的共同属性color返回对象地址
11 public static AbstractMemoryCard getMemoryCard(String color) {
12 //如果获取的color不为空直接返回color
13 if(map.get(color)!=null) {
14 return map.get(color);
15 }else {
16 //为空则初始化color并将其放入享元池中
17 AbstractMemoryCard amc=new MemoryCard(color);
18 map.put(color, amc);
19 return amc;
20 }
21 }
22
23 }
5.客户端
1 package com.etc;
2
3 public class Client {
4
5 public static void main(String[] args) {
6
7 //因为color属性为共享属性,所以在此已经初始化了color的值为黑色
8 AbstractMemoryCard amc=Factory.getMemoryCard("黑色");
9 //color的值已经存在,所以返回相同的对象
10 AbstractMemoryCard amc2=Factory.getMemoryCard("黑色");
11 System.out.println(amc==amc2?"两个对象相同":"两个对象不相同");
12
13 ExternalState state=new ExternalState(16,"三星");
14 ExternalState state2=new ExternalState(32,"闪迪");
15 //信息展示
16 amc.showMessage(state);
17 amc2.showMessage(state2);
18 }
19
20 }
效果截图:
享元模式优缺点:
优点:
1.极大的减少了内存中对象的数量
2.相同或相似的对象在内存中只占一份,极大的节约资源,提高了系统性能。
3.外部状态相对独立,不会影响内部状态。
缺点:
1.模式较复杂,使程序逻辑复杂化
2.为了节省内存,共享了内部状态,分离出外部状态,而读取外部状态使运行时间变长,用时间换取了空间。
适用场景:
1.可以在任何"池"中操作,比如线程池,数据库连接池。
2.String类的设计也是享元模式