模式导读:
世上没有相同的两片叶子,尽管它们可能非常相似,无论是颜色,大小亦或是重量等等,也会有不同之处,比如纹理,厚度等等。当我们需要将两片叶子用语言描述出来时,你是会选择两者分开描述,从颜色到厚度,从抽象到具体等等还是会选择两者同时描述,将共同点抽取出来然后细话两者不同。显然后者相比于前者既省时间又提高了辨识度,效率明显提升。享元模式在生活中随处可见,抽取相同属性放入一个容器以便共享,并且可以保证该属性不会随外部环境变化而发生变化。这便是享元模式。
核心:
享元模式以共享的方式高效的支持大量细粒度对象的重用。
享元对象能做到共享的关键是区分了内部状态和外部状态。
内部状态:可以共享,不会随环境变化而变化。
外部状态:不可以共享,会随环境变化而变化。
参考类图:
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类的设计也是享元模式