GOF23设计模式之享元模式(flyweight)

一、享元模式概述

  内存属于稀缺资源,不要随便浪费。如果有很多个完全相同或相似的对象,可以通过享元模式,节省内存。

  享元模式核心:

    (1)享元模式可以共享的、方式高效的支持大量细粒度对象的重用; 

    (2)享元对象能做到共享的关键是区分了内部状态和外部状态:

        ① 内部状态:可以共享,不会随环境变化而改变

        ② 外部状态:不能共享,会随环境变化而改变

二、享元模式实现

  (1)FlyWeightFactory享元工厂类

      创建并管理享元对象,享元池一般设计成键值对。

  (2)FlyWeight抽象享元类

      通常是一个接口,声明公共方法,这些方法可以向外界提供对象的内部状态,设置外部状态。

  (3)ConcreteFlyWeight具体享元类

      内部状态提供成员变量进行存储。

  (4)UnShareConcreteFlyWeight非共享享元类

      不能被共享的子类可以设计成非共享享元类。

三、元模式场景导入示例代码

  场景:围棋中每一个棋子都是一个对象。棋子有如下属性:

       颜色 状态 大小(这些是可以共享的)称之为:内部状态

         位置(这是不可以共享的)称之为:外部状态

 1 /**
 2  * 抽象享元类FlyWeight
 3  * @author CL
 4  *
 5  */
 6 public interface ChessFlyWeight {
 7     void setColor(String color);
 8     String getColor();
 9     void display(Coordinate c);
10 }
11 
12 /**
13  * ConcreteFlyWeight具体享元类
14  * 内部状态
15  * @author CL
16  *
17  */
18 class ConcreteChess implements ChessFlyWeight {
19 
20     private String color;
21     
22     public ConcreteChess(String color) {
23         this.color = color;
24     }
25 
26     @Override
27     public void setColor(String color) {
28         this.color = color;
29     }
30 
31     @Override
32     public String getColor() {
33         return color;
34     }
35 
36     @Override
37     public void display(Coordinate c) {
38         System.out.println("棋子的颜色: "+color);
39         System.out.println("棋子的位置: ["+c.getX()+","+c.getY()+"]");
40     }
41     
42 }
 1 import java.util.HashMap;
 2 import java.util.Map;
 3 
 4 /**
 5  * 享元工厂类
 6  * @author CL
 7  *
 8  */
 9 public class ChessFlyWeightFactory {
10     //享元池
11     private static Map<String, ChessFlyWeight> map = 
12             new HashMap<String, ChessFlyWeight>();;
13 
14     public static ChessFlyWeight getChess(String color) {
15         if (map.get(color) != null) {
16             return map.get(color);
17         } else {
18             ChessFlyWeight cfw = new ConcreteChess(color);
19             map.put(color, cfw);
20             return cfw;
21         }
22     }
23     
24 }
 1 /**
 2  * 外部状态
 3  *     UnShareFlyWeight非共享享元类
 4  * @author CL
 5  *
 6  */
 7 public class Coordinate {
 8     private int x, y;
 9 
10     public Coordinate(int x, int y) {
11         this.x = x;
12         this.y = y;
13     }
14 
15     public int getX() {
16         return x;
17     }
18 
19     public void setX(int x) {
20         this.x = x;
21     }
22 
23     public int getY() {
24         return y;
25     }
26 
27     public void setY(int y) {
28         this.y = y;
29     }
30 }

  测试:

 1 /**
 2  * 测试享元模式
 3  * @author CL
 4  *
 5  */
 6 public class Client {
 7     
 8     public static void main(String[] args) {
 9         ChessFlyWeight c1 = ChessFlyWeightFactory.getChess("黑色");
10         ChessFlyWeight c2 = ChessFlyWeightFactory.getChess("黑色");
11         System.out.println(c1);
12         System.out.println(c2);    //c1 和 c2 是同一对象
13         
14         System.out.println("--------------------");
15         c1.display(new Coordinate(10, 10));
16         c2.display(new Coordinate(20, 20));
17     }
18 
19 }

  控制台输出:

com.caolei.flyweight.ConcreteChess@759ebb3d
com.caolei.flyweight.ConcreteChess@759ebb3d
--------------------
棋子的颜色: 黑色
棋子的位置: [10,10]
棋子的颜色: 黑色
棋子的位置: [20,20]

四、享元模式优缺点

  优点:

    (1)极大的减少内存中对象的数量;

    (2)相同或相似对象内存中只存一份,极大的节约资源,提高系统性能;

    (3)外部状态相对独立,不影响内部状态。

  缺点:

    (1)模式较复杂,使程序逻辑复杂化;

    (2)为了节省内存,共享了内部状态,分离出外部状态,而读取外部状态使运行时间较长,用时间换空间。

五、享元模式常见开发应用场景

  (1)享元模式由于其共享的特性,可以在任何“池”中操作,比如:线程池、数据库连接池;

  (2)String类的设计也是享元模式;

  (3)…………

原文地址:https://www.cnblogs.com/cao-lei/p/8327935.html