享元模式(Flyweight Pattern)

Posted 小风的笔记

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了享元模式(Flyweight Pattern)相关的知识,希望对你有一定的参考价值。

享元模式(运用共享技术有效的支持大量细粒度的对象)

  • 优点:大大减少对象的创建,降低系统的内存,使效率提高。
  • 缺点:提高了系统的复杂度,需要分离出内蕴状态和外蕴状态,而且外蕴状态具有固有化的性质,不应该随着内蕴状态的变化而变化,否则会造成系统的混乱。
  • 享元模式的定义提出了两个要求,细粒度和共享对象。因为要求细粒度,所以不可避免地会使对象数量多且性质相近,此时我们就将这些对象的信息分为两个部分:内部状态和外部状态。
    内蕴状态:对象共享出来的信息,存储在享元对象内部并且不会随环境的改变而改变。
    外蕴状态:对象得以依赖的一个标记,是随环境改变而改变的、不可共享的状态。
  • 享元模式的主要角色
    抽象享元角色:为具体享元角色规定了必须实现的方法,非享元的外蕴状态以参数的形式通过此方法传入。
    具体享元角色:实现抽象享元角色的接口。
    享元工厂角色:负责创建和管理享元角色。当客户对象请求一个享元对象时,享元工厂检查系统中是否存在符合要求的享元对象,如果存在则提供给客户;如果不存在,则创建一个新的享元对象。
    非享元角色:是不可以共享的外蕴状态,它以参数的形式注入具体享元的相关方法中。
  • 例子:围棋只有黑白两色,所以棋子颜色就是棋子的内蕴状态;而各个棋子之间的差别就是位置的不同,我们落子嘛,落子颜色是定的,但位置是变化的,所以方位坐标就是棋子的外蕴状态,类图如下:
  • 代码如下

非享元角色

/**
 * 棋盘位置(外蕴状态)
 */
public class Location {
    private int x;
    private int y;
    public Location(int x, int y) {
        this.x = x;
        this.y = y;
    }
    public int getX() {
        return x;
    }
    public void setX(int x) {
        this.x = x;
    }
    public int getY() {
        return y;
    }
    public void setY(int y) {
        this.y = y;
    }
}

抽象享元角色

/**
* 棋子
*/
public interface ChessPieces {
   void downPieces(Location location);
}

具体享元角色

/**
 * 白棋(内蕴状态)
 */
public class WhitePieces implements ChessPieces {
    public WhitePieces() {
        System.out.println("+++生成白棋对象+++");
    }
    @Override
    public void downPieces(Location location) {
        System.out.println("白棋对象已经存在,被成功获取!");
        System.out.println("坐标X="+location.getX()+";Y="+location.getY());
    }
}
/**
 * 黑棋(内蕴状态)
 */
public class BlackPieces implements ChessPieces {
    public BlackPieces() {
        System.out.println("+++生成黑棋对象+++");
    }
    @Override
    public void downPieces(Location location) {
        System.out.println("黑棋对象已经存在,被成功获取!");
        System.out.println("坐标X="+location.getX()+";Y="+location.getY());
    }
}

享元工厂角色

/**
 * 工厂
 */
public class PiecesFactory {
    private static final String WRITE = "白棋";
    private static final String BLACK = "黑棋";
    Map<String, ChessPieces> pieces = new HashMap<>();
    // 获取棋子对象
    public ChessPieces getPieceInstance(String color) {
        if(pieces.get(color) == null) {
            if(color == WRITE) {
                WhitePieces whitePieces = new WhitePieces();
                pieces.put(color, whitePieces);
            }else if(color == BLACK){
                BlackPieces blackPieces = new BlackPieces();
                pieces.put(color, blackPieces);
            }else {
                System.out.println("不存在的颜色");
                return null;
            }
        }
        return pieces.get(color);
    }
}

测试

public class Test {
    private static final String WRITE = "白棋";
    private static final String BLACK = "黑棋";

    public static void main(String[] args) {
        try {
            PiecesFactory factory = new PiecesFactory();
            System.out.println("---游戏开始---");
            String color = WRITE;
            while (true) {
                if (color.equals(WRITE)) {
                    System.out.println("---白棋请落子---");
                } else {
                    System.out.println("---黑棋请落子---");
                }
                System.out.println("请输入X坐标");
                Scanner scanner1 = new Scanner(System.in);
                int x = scanner1.nextInt();
                System.out.println("请输入y坐标");
                Scanner scanner2 = new Scanner(System.in);
                int y = scanner2.nextInt();
                ChessPieces chessPieces = factory.getPieceInstance(color);
                chessPieces.downPieces(new Location(x, y));
                if (WRITE.equals(color)) {
                    color = BLACK;
                } else {
                    color = WRITE;
                }
            }
        } catch (Exception e) {
            System.out.println("---游戏结束---");
        }
    }
}
// 运行结果
---游戏开始---
---白棋请落子---
请输入X坐标
1
请输入y坐标
2
+++生成白棋对象+++
白棋对象已经存在,被成功获取!
坐标X=1;Y=2
---黑棋请落子---
请输入X坐标
4
请输入y坐标
5
+++生成黑棋对象+++
黑棋对象已经存在,被成功获取!
坐标X=4;Y=5
---白棋请落子---
请输入X坐标
3
请输入y坐标
3
白棋对象已经存在,被成功获取!
坐标X=3;Y=3
---黑棋请落子---
请输入X坐标
5
请输入y坐标
5
黑棋对象已经存在,被成功获取!
坐标X=5;Y=5
---白棋请落子---
请输入X坐标

eee
---游戏结束---

运行上面代码,可以发现,在一局游戏中,只会在一开始生成白棋和黑棋对象两个对象,后面的落子只需要在工厂之中获取就好。

以上是关于享元模式(Flyweight Pattern)的主要内容,如果未能解决你的问题,请参考以下文章

享元模式(Flyweight Pattern)

13享元模式(FlyWeight Pattern)

二十四种设计模式:享元模式(Flyweight Pattern)

享元模式(Flyweight Pattern)

尚硅谷设计模式学习(12)---[享元模式(Flyweight Pattern)]

秒懂设计模式之享元模式(Flyweight Pattern)