相关推荐recommended
笨蛋学设计模式结构型模式-享元模式【13】
作者:mmseoamin日期:2024-01-25

结构型模式-享元模式

    • 7.7享元模式
      • 7.7.1概念
      • 7.7.2场景
      • 7.7.3优势 / 劣势
      • 7.7.4享元模式可分为
      • 7.7.5享元模式
      • 7.7.6实战
        • 7.7.6.1题目描述
        • 7.7.6.2输入描述
        • 7.7.6.3输出描述
        • 7.7.6.4代码
        • 8.1.7总结
        • 享元模式

          7.7享元模式

          7.7.1概念

          ​ 享元模式是通过共享对象减少内存使用,来提高程序性能。在此模式中,分为内部状态和外部状态,其中相似的对象被存储在享元对象内部,并对于所有享元对象都是相同的,且状态通常是不变的。只在需要时内部共享,而不是每次创建新的对象。而外部状态是享元对象依赖的,可能变化的部分。这部分状态不存储在享元对象内部,而是在使用享元对象时传递给对象。

          7.7.2场景

          ​ 在棋类游戏中,棋子可以看作是享元对象,因为棋子与棋子之间有着相同的属性和方法,例如在颜色、大小、移动规则上都有着相同的特质。因此在棋类游戏中,可以使用享元模式来共享相同的棋子对象,避免创建大量的棋子对象,从而提高游戏性能。

          7.7.3优势 / 劣势

          • 减少内存消耗:通过共享公共状态,减少创建对象的数量
          • 提升性能:通过共享对象来减少内存中对象的数量,可以减少垃圾回收的频率
            • 线程安全问题:享元模式的对象可能会导致线程安全问题,需要采取一定的措施
            • 适用场景有限:享元模式存在大量相似对象的场景,若不适用,则会导致性能下降,代码复杂度增加

              7.7.4享元模式可分为

              • 享元接口Flyweight:所有具体享元类的共享接口,通常包含对外部状态的操作
              • 具体享元类ConcreteFlyweight:继承Flyweight类或实现享元接口,包含内部状态
              • 享元工厂类FlyweightFactory:创建并管理享元对象,当用户请求时,提供已创建的实例或者创建一个
              • 客户端Client:维护外部状态,在使用享元对象时,将外部状态传递给享元对象

                7.7.5享元模式

                package com.technologystatck.designpattern.mode.flyweight;
                import java.util.HashMap;
                import java.util.Map;
                public class Flyweight {
                    public static void main(String[] args) {
                        //实例化享元工厂对象
                        FlyweightFactory factory = new FlyweightFactory();
                        //获取或创建享元对象,并传递外部状态
                        Flyweights flyweightA = factory.getFlyweight("A");
                        flyweightA.operation("External State A");
                        Flyweights flyweightB = factory.getFlyweight("B");
                        flyweightB.operation("External State B");
                        Flyweights flyweightC = factory.getFlyweight("A");
                        flyweightC.operation("External State C");
                    }
                }
                //创建享元接口
                interface Flyweights {
                    //操作外部状态
                    void operation(String extrinsicState);
                }
                //实现具体享元类,存储内部状态
                class ConcreteFlyweight implements Flyweights{
                    //内部状态
                    private String intrinsicState;
                    public ConcreteFlyweight(String intrinsicState) {
                        this.intrinsicState = intrinsicState;
                    }
                    @Override
                    public void operation(String extrinsicState) {
                        System.out.println("Intrinsic State: "+intrinsicState+",External State: "+extrinsicState);
                    }
                }
                //创建享元工厂类,创建并管理Flyweight对象,
                //当用户请求一个Flyweight时,享元工厂会提供一个已经创建的实例或创建一个
                class FlyweightFactory{
                    private Map flyweights=new HashMap<>();
                    public Flyweights getFlyweight(String key){
                        //若没有享元对象时,就将传进来的key值创建一个
                        if(!flyweights.containsKey(key)){
                            flyweights.put(key,new ConcreteFlyweight(key));
                        }
                        return flyweights.get(key);
                    }
                }
                

                7.7.6实战

                7.7.6.1题目描述

                ​ 在一个图形编辑器中,用户可以绘制不同类型的图形,包括圆形(CIRCLE)、矩形(RECTANGLE)、三角形(TRIANGLE)等。现在,请你实现一个图形绘制程序,要求能够共享相同类型的图形对象,以减少内存占用。

                7.7.6.2输入描述

                输入包含多行,每行表示一个绘制命令。每个命令包括两部分:

                图形类型(Circle、Rectangle 或 Triangle)

                绘制的坐标位置(两个整数,分别表示 x 和 y)

                7.7.6.3输出描述

                对于每个绘制命令,输出相应图形被绘制的位置信息。如果图形是首次绘制,输出 “drawn at”,否则输出 “shared at”。

                7.7.6.4代码
                package com.technologystatck.designpattern.mode.flyweight;
                import java.util.HashMap;
                import java.util.Map;
                import java.util.Scanner;
                public class Test {
                    public static void main(String[] args) {
                        Scanner scanner = new Scanner(System.in);
                        //创建工厂实例
                        GraphicFactory graphicFactory = new GraphicFactory();
                        while(scanner.hasNext()){
                            String command = scanner.nextLine();
                            //定义一个静态方法
                            proessCommand(graphicFactory,command);
                        }
                    }
                    public static void proessCommand(GraphicFactory graphicFactory,String command){
                        //定义数组存放类型变量
                        String[] parts = command.split(" ");
                        DrawType drawType=DrawType.valueOf(parts[0]);
                        int x=Integer.parseInt(parts[1]);
                        int y=Integer.parseInt(parts[2]);
                        //
                        Graphic graphic=graphicFactory.getGraphic(drawType);
                        graphic.draw(new ConcretePosition(x,y));
                        ((ConcreteGraphic) graphic).setFirstTime(false);
                    }
                }
                //使用枚举创建图形类型
                enum DrawType{
                    CIRCLE,RECTANGLE,TRIANGLE;
                }
                //创建坐标类
                class ConcretePosition{
                    //内部状态
                    private int x;
                    private int y;
                    public ConcretePosition() {
                    }
                    public ConcretePosition(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;
                    }
                }
                //创建图像享元接口
                interface Graphic{
                    //外部状态
                    void draw(ConcretePosition concretePosition);
                }
                //创建具体图形实现类
                class ConcreteGraphic implements Graphic{
                    //内部状态
                    private DrawType drawType;
                    public ConcreteGraphic(DrawType drawType) {
                        this.drawType = drawType;
                    }
                    //检查是否是第一次绘制该图形
                    private Boolean isFirstTime=true;
                    public Boolean getFirstTime() {
                        return isFirstTime;
                    }
                    public void setFirstTime(Boolean firstTime) {
                        isFirstTime = firstTime;
                    }
                    //描绘图形方法
                    @Override
                    public void draw(ConcretePosition concretePosition) {
                        System.out.println(drawType+(isFirstTime ? "drawn":"shared")+" at ("+
                                concretePosition.getX()+" , "+concretePosition.getY()+")");
                    }
                }
                //创建享元图形工厂
                class GraphicFactory{
                    private Map graphicEditors=new HashMap<>();
                    //检查是否已创建对象
                    public Graphic getGraphic(DrawType drawType){
                        //若时第一次创建,就实例化一个新对象,否则就返回已经创建的对象。
                        if(!graphicEditors.containsKey(drawType)){
                            graphicEditors.put(drawType,new ConcreteGraphic(drawType));
                        }
                        return graphicEditors.get(drawType);
                    }
                }
                

                8.1.7总结

                • 享元模式

                • 优点:通过减少创建对象的数量以此来减少内存消耗,提高程序的性能
                • 总结:分为外部状态和内部状态,内部状态主要是大量相似的对象,外部状态是变化较大的对象
                • 场景:用于包含大量相似对象,且对象的内部状态可以共享,外部状态变化较大时