欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

08. 23种经典设计模式-22-享元模式

程序员文章站 2022-06-04 23:17:13
...

1. 享元模式

Use sharing to support large numbers of fine-grained objects efficiently. (使用共享对象可有效地支持大量的细粒度的对象)

1.1 享元模式核心思想

  • 利用jvm缓存,解决应用中大量重复对象的内存浪费问题
  • 享元标准模式并不是太好设计,享元思想很好实现

1.2 享元模式类图

  • Flyweight: 抽象享元角色, 负责定义内部状态和外部状态
    • 内部状态: 不会因环境和场景而变化的状态
    • 外部状态: 会根据环境和场景变化的状态
  • ConcreteFlyweight: 具体享元角色, 可共享的对象
  • unSharedConcreteFlyweight: 不可共享的享元角色, 非必须. 享元模式不要求对象必须支持共享
  • FlyweightFactory: 享元工厂, 实现缓存逻辑
    [外链图片转存失败(img-Lk0mMbQJ-1566894907377)(https://raw.githubusercontent.com/zongf0504/blog-images/master/images/design-parttern/ldp-flyweight-01.png)]

1.3 享元模式优缺点

  • 优点: 节省jvm 内存
  • 缺点: 内部状态外部状态不容易区分,比较难以按照标准模式进行设计

1.4 享元模式适用场景

  • 系统中存在大量的相似对象
  • 对象缓存池的设计
  • 广泛用于池技术,如数据库连接池, 字符串常量池等

2. 享元模式用例

对于享元模式, 笔者查阅了很多资料, 也没有发现很好的应用案例. 笔者认为, 了解享元模式核心思想是为了解决大量重复对象对jvm内存的浪费即可.

我们来举一个围棋的例子,一个棋盘上每个坐标上都有黑子或白子,区别在于坐标. 如果程序中为每个位置都创建一个棋子对象,那么显然时内存浪费.

2.1 类图

  • 只实现共享角色, 不实现非共享角色.
  • 内部状态: 颜色
  • 外部状态: 棋盘, 坐标

[外链图片转存失败(img-qF78VNlD-1566894907378)(https://raw.githubusercontent.com/zongf0504/blog-images/master/images/design-parttern/ldp-flyweight-02.png)]

2.2 抽象享元角色-

public abstract class AbsGoPiece {

    // 抽象落子方法, 传入落子坐标: 哪个棋盘的哪行哪列
    public abstract void put(GoPiece[][] goBoard, int x, int y);
}

2.3 具体享元角色-GoPiece

public class GoPiece extends AbsGoPiece {

    private String color;

    public GoPiece(String color) {
        this.color = color;
    }

    public String getColor() {
        return color;
    }

    @Override
    public void put(GoPiece[][] goBoard, int x, int y) {
        goBoard[x][y] = this;
    }
}

2.4 享元工厂类

享元模式解决的是节省jvm内存,因此缓存要使用Map对象.

public class GoPieceFactory {

    private static HashMap<String, GoPiece> cacheMap = new HashMap<>();

    public static GoPiece getGoPiece(String color) {

        if (cacheMap.containsKey(color)) {
            return cacheMap.get(color);
        }else {
            GoPiece goPieceFW = new GoPiece(color);
            cacheMap.put(color, goPieceFW);
            return goPieceFW;
        }
    }
}

2.5 测试

public class TestFlyweight {

    @Test
    public void test(){

        // 创建棋盘对象
        GoPiece[][] goBoard = new GoPiece[3][3];

        for (int i = 0; i < 3; i++) {
            GoPiece blackPiece = GoPieceFactory.getGoPiece("黑色");
            blackPiece.put(goBoard, 0,i);
        }

        for (int i = 0; i < 3; i++) {
            GoPiece whitePiece = GoPieceFactory.getGoPiece("白色");
            whitePiece.put(goBoard, 1, i);
        }

        for (int i = 0; i < 3; i++) {
            GoPiece blackPiece = GoPieceFactory.getGoPiece("黑色");
            blackPiece.put(goBoard, 2,i);
        }

        printGoBoard(goBoard);
    }

    private void printGoBoard(GoPiece[][] goBoard) {
        for (int i = 0; i < goBoard.length; i++) {
            for (int j = 0; j < goBoard[i].length; j++) {
                GoPiece goPieceFWS = goBoard[i][j];
                if (goPieceFWS != null) {
                    System.out.print(goPieceFWS.getColor() + "@" + goPieceFWS.hashCode() + " ,");
                }else {
                    System.out.print("              ,");
                }
            }
            System.out.println();
        }

    }

}

2.6 测试输出

从测试结果中发现, 对象只有两个

黑色@233530418 ,黑色@233530418 ,黑色@233530418 ,
白色@683287027 ,白色@683287027 ,白色@683287027 ,
黑色@233530418 ,黑色@233530418 ,黑色@233530418 ,
相关标签: 23种设计模式