Java设计模式—享元模式

2020-08-11  本文已影响0人  怡红快绿

享元模式采用共享机制来避免大量拥有相同内容对象的开销。这种开销最常见、最直观的就是内存的损耗。享元对象能做到共享的关键是区分内蕴状态(Internal State)和外蕴状态(External State)。

组成结构

享元模式一般有三个角色:

简单应用

以象棋游戏为例,假设我们把每颗棋子看成是一个对象,那么每开启一个棋局需要创建32个棋子对象,那如果同时存在一百万个棋局的话就很可怕了!!!我们试着用享元模式解决这个问题。

首先划分外蕴状态和内蕴状态

外蕴状态:不同的棋子角色是不确定的,创建棋子的时候才会确认是什么角色。
内蕴状态:棋子的形状和大小基本是不会变化的,不会随着棋子角色变化而变化。

1、抽象享元(Flyweight)角色

定义一个创建棋子的接口

public interface IChess {
    /**
     * 棋子信息
     */
    void info();
}
2、具体享元(ConcreteFlyweight)角色

实现棋子的创建并打印棋子信息

public class Chess implements IChess {

    public static final String TAG = "Chess";

    //可变
    private String role; //棋子角色

    //不可变
    private String shape = "CIRCLE";  //棋子形状
    private int radius = 100; //棋子半径大小

    public Chess(String role) {
        this.role = role;
    }

    @Override
    public void info() {
        Log.d(TAG, String.format("角色%s,形状%s,大小%d", role, shape, radius));
    }
}
3、享元工厂(FlyweightFactory)角色

负责创建棋子,使用HashMap保存已创建的棋子达到复用目的

public class ChessFactory {

    private static HashMap<String, Chess> chessHashMap = new HashMap<>(); //负责存储共享对象

    //如果共享Map内已经存在role角色的棋子,直接复用;否则创建新棋子
    public static Chess getChess(String role) {
        Chess chess = chessHashMap.get(role);
        if (chess == null) {
            Log.d(TAG, "=================创建一个新的棋子=================");
            chess = new Chess(role);
            chessHashMap.put(role, chess);
        }
        return chess;
    }
}

随机创建30个棋子(六种角色),查看程序运行结果:

public void button(View view) {
    String[] roles = {"将", "帅", "车", "马", "炮", "兵"};
    //创建30个棋子
    for (int i = 0; i < 30; i++) {
        ChessFactory.getChess(roles[(int) (Math.random() * 1000) % 6]).createChess();
    }
}
2020-08-11 15:20:56.774 16675-16675/com.android.multidex D/Chess: =================创建一个新的棋子=================
2020-08-11 15:20:56.774 16675-16675/com.android.multidex D/Chess: 角色车,形状CIRCLE,大小100
2020-08-11 15:20:56.774 16675-16675/com.android.multidex D/Chess: =================创建一个新的棋子=================
2020-08-11 15:20:56.774 16675-16675/com.android.multidex D/Chess: 角色炮,形状CIRCLE,大小100
2020-08-11 15:20:56.774 16675-16675/com.android.multidex D/Chess: =================创建一个新的棋子=================
2020-08-11 15:20:56.775 16675-16675/com.android.multidex D/Chess: 角色马,形状CIRCLE,大小100
2020-08-11 15:20:56.775 16675-16675/com.android.multidex D/Chess: =================创建一个新的棋子=================
2020-08-11 15:20:56.775 16675-16675/com.android.multidex D/Chess: 角色兵,形状CIRCLE,大小100
2020-08-11 15:20:56.775 16675-16675/com.android.multidex D/Chess: 角色炮,形状CIRCLE,大小100
2020-08-11 15:20:56.776 16675-16675/com.android.multidex D/Chess: 角色马,形状CIRCLE,大小100
2020-08-11 15:20:56.776 16675-16675/com.android.multidex D/Chess: =================创建一个新的棋子=================
2020-08-11 15:20:56.776 16675-16675/com.android.multidex D/Chess: 角色将,形状CIRCLE,大小100
2020-08-11 15:20:56.776 16675-16675/com.android.multidex D/Chess: 角色兵,形状CIRCLE,大小100
2020-08-11 15:20:56.776 16675-16675/com.android.multidex D/Chess: 角色将,形状CIRCLE,大小100
2020-08-11 15:20:56.776 16675-16675/com.android.multidex D/Chess: =================创建一个新的棋子=================
2020-08-11 15:20:56.777 16675-16675/com.android.multidex D/Chess: 角色帅,形状CIRCLE,大小100
2020-08-11 15:20:56.777 16675-16675/com.android.multidex D/Chess: 角色帅,形状CIRCLE,大小100
2020-08-11 15:20:56.777 16675-16675/com.android.multidex D/Chess: 角色车,形状CIRCLE,大小100
2020-08-11 15:20:56.777 16675-16675/com.android.multidex D/Chess: 角色帅,形状CIRCLE,大小100
2020-08-11 15:20:56.778 16675-16675/com.android.multidex D/Chess: 角色车,形状CIRCLE,大小100
2020-08-11 15:20:56.778 16675-16675/com.android.multidex D/Chess: 角色将,形状CIRCLE,大小100
2020-08-11 15:20:56.778 16675-16675/com.android.multidex D/Chess: 角色马,形状CIRCLE,大小100
2020-08-11 15:20:56.778 16675-16675/com.android.multidex D/Chess: 角色马,形状CIRCLE,大小100
2020-08-11 15:20:56.779 16675-16675/com.android.multidex D/Chess: 角色帅,形状CIRCLE,大小100
2020-08-11 15:20:56.779 16675-16675/com.android.multidex D/Chess: 角色帅,形状CIRCLE,大小100
2020-08-11 15:20:56.779 16675-16675/com.android.multidex D/Chess: 角色兵,形状CIRCLE,大小100
2020-08-11 15:20:56.780 16675-16675/com.android.multidex D/Chess: 角色马,形状CIRCLE,大小100
2020-08-11 15:20:56.780 16675-16675/com.android.multidex D/Chess: 角色马,形状CIRCLE,大小100
2020-08-11 15:20:56.780 16675-16675/com.android.multidex D/Chess: 角色炮,形状CIRCLE,大小100
2020-08-11 15:20:56.780 16675-16675/com.android.multidex D/Chess: 角色将,形状CIRCLE,大小100
2020-08-11 15:20:56.780 16675-16675/com.android.multidex D/Chess: 角色将,形状CIRCLE,大小100
2020-08-11 15:20:56.781 16675-16675/com.android.multidex D/Chess: 角色马,形状CIRCLE,大小100
2020-08-11 15:20:56.781 16675-16675/com.android.multidex D/Chess: 角色马,形状CIRCLE,大小100
2020-08-11 15:20:56.781 16675-16675/com.android.multidex D/Chess: 角色车,形状CIRCLE,大小100
2020-08-11 15:20:56.781 16675-16675/com.android.multidex D/Chess: 角色马,形状CIRCLE,大小100

从结果可以看出,每个角色的棋子都只有在第一次使用的时候需要创建,也就是说棋子对象的个数只与角色数量有关。这样就成功实现了对象的共享复用,减少了因重复创建相同内容的对象带来的内存开销。

优缺点

优点
缺点

为了使对象可以共享,需要划分内蕴状态和外蕴状态,使得程序的设计变得复杂。

享元模式与对象池的区别

相同点:

享元模式和对象池的最终目标是相同的,都是为了减少对象的数量,减少内存的使用。它们都是通过维护和共享一组对象实现对象的复用。

不同点:

享元模式是结构型模式。它把可以变化的状态剥离出来并对外提供接口,并且共享不变的东西。享元对外提供的接口常常会包含一个String类型的参数,通常参数与对象是一对一的关系。
而对象池是构造型模式,侧重于提供整个对象实例。对调用者而言对象池提供的对象都没有区别,这个可以用,那个也可以用。

上一篇 下一篇

猜你喜欢

热点阅读