享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。
享元模式尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象。
假设一个场景:有一盘围棋,有黑白二色旗子,对于任意一方来说,每一个棋子长得都是一样的,但是我们需要用位置来区分每个棋子。如果我们为每一个棋子创建一个对象,显然会创建大量的对象,这增加了大量的小对象,造成了对象管理的困难。所以我们引入了享元模式,把棋子共有的颜色等属性抽象出来,把棋子不共有的,如位置等,另外构成一个类。
FlyWeight接口
1 package top.bigking.flyWeight; 2 3 /** 4 * @Author ABKing 5 * @since 2020/2/25 下午10:12 6 **/ 7 public interface FlyWeight { 8 void getColor(); 9 void getPosition(UnsharedConcreteFlyWeight position); 10 }
FlyWeight的实现类,ConcreteFlyWeight类,增加了内部状态(共有的)
1 package top.bigking.flyWeight; 2 3 /** 4 * @Author ABKing 5 * @since 2020/2/25 下午10:13 6 * 内部状态 ConcreteFlyWeight 7 **/ 8 public class ConcreteFlyWeight implements FlyWeight { 9 private String color; 10 11 public ConcreteFlyWeight(String color) { 12 this.color = color; 13 } 14 15 @Override 16 public void getColor() { 17 System.out.println("颜色是: " + color); 18 } 19 20 @Override 21 public void getPosition(UnsharedConcreteFlyWeight position) { 22 System.out.println("位置是: " + position); 23 } 24 25 26 }
外部状态,UnsharedConcreteFlyWeight类
1 package top.bigking.flyWeight; 2 3 /** 4 * @Author ABKing 5 * @since 2020/2/25 下午10:14 6 * 外部状态 UnsharedConcreteFlyWeight 7 **/ 8 public class UnsharedConcreteFlyWeight { 9 private String x, y; 10 11 public UnsharedConcreteFlyWeight(String x, String y) { 12 this.x = x; 13 this.y = y; 14 } 15 16 @Override 17 public String toString() { 18 return "x是" + x + ", y是" + y; 19 } 20 21 public String getX() { 22 return x; 23 } 24 25 public void setX(String x) { 26 this.x = x; 27 } 28 29 public String getY() { 30 return y; 31 } 32 33 public void setY(String y) { 34 this.y = y; 35 } 36 }
享元模式通常与工厂模式结合起来使用,写一个FlyWeightFactory类
1 package top.bigking.flyWeight; 2 3 import java.util.HashMap; 4 import java.util.Map; 5 6 /** 7 * @Author ABKing 8 * @since 2020/2/25 下午10:34 9 **/ 10 public class FlyWeightFactory { 11 //享元池 12 private static Map<String, FlyWeight> map = new HashMap<>(); 13 14 public static FlyWeight getFlyWeight(String color){ 15 FlyWeight flyWeight = map.get(color); 16 if(flyWeight != null){//池中有对象 17 return flyWeight; 18 }else {//池中无对象 19 FlyWeight fw = new ConcreteFlyWeight(color); 20 map.put(color, fw); 21 return fw; 22 } 23 } 24 }
JUnit单元测试:
1 package top.bigking.flyWeight; 2 3 import org.junit.Test; 4 5 /** 6 * @Author ABKing 7 * @since 2020/2/25 下午10:40 8 **/ 9 public class TestFlyWeight { 10 @Test 11 public void testFlyWeight(){ 12 FlyWeight flyWeight = FlyWeightFactory.getFlyWeight("黑色"); 13 FlyWeight flyWeight2 = FlyWeightFactory.getFlyWeight("黑色"); 14 System.out.println(flyWeight == flyWeight2); 15 flyWeight.getColor(); 16 flyWeight2.getColor(); 17 flyWeight.getPosition(new UnsharedConcreteFlyWeight("10", "15")); 18 flyWeight2.getPosition(new UnsharedConcreteFlyWeight("20", "20")); 19 } 20 }
优点:
- 极大减少内存中对象的数量
- 相同或相似对象内存中只存一份,极大地节约资源,提高系统性能。
- 外部状态相对独立,不影响内部状态。
缺点:
- 模式较复杂,使程序逻辑复杂化
- 为了节省内存,共享了内部状态,分理出外部状态,而读取外部状态使运行时间边长。用时间换取了空间。
- 由于是共享同一个对象,所以后一个改变外部状态会影响前一个的外部状态。
享元模式开发应用中的场景:
享元模式由于其共享的特性,可以在任何池中操作,比如:线程池,数据库连接池
String类的设计也是享元模式