美文网首页
享元模式-java

享元模式-java

作者: JW2015 | 来源:发表于2022-02-22 17:47 被阅读0次

    概念:

    享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。它属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。

    享元模式存在两种状态:
    内部状态:不会随着环境的改变而改变的的可共享部分
    外部状态:指随着环境改变而改变的不可以共享的部分
    享元模式的实现要领就是区分应用中的两种状态,将外部状态外部化。

    享元模式的角色:

    抽象享元角色(Flyweight):是一个接口或者抽象类,在抽象享元类中声明具体享元类公共的方法,这些方法可以向外界提供享元对象的内部数据(内部状态),同时也可以通过这些方法设置外部数据(外部状态)

    具体享元角色(Concrete Flyweight):实现了抽象享元类,称为享元对象;在具体享元类中为内部状态提供了存储空间。通常我们可以结合单例模式来设计具体享元类,为每一个具体享元类提供唯一的享元对象。

    非享元角色(Unsharable Flyweight):并不是所有的抽象享元类的子类都需要被共享,不能被共享的子类可设计为非共享具体享元类。当需要一个非共享具体享元类的对象时可以直接通过实例化创建

    享元工厂角色(Flyweight Factory):负责创建和管理享元角色。当客户对象请求一个享元对象时,享元工厂检查系统中是否存在符合要求的享元对象,如果存在则提供给客户;如果不存在的话,创建一个新的享元对象

    实现案例:

    以小游戏俄罗斯方块为例,提供抽象享元角色(AbstractBox)、具体享元角色(图形LBox、图形ZBox)、享元工厂角色(BoxFactory)。游戏中,不断的有不同颜色的重复图形出现,这里使用享元模式进行实现。不同颜色为外部状态,参数传递进行实现。

    //抽象享元角色
    public abstract class AbstractBox {
        //获取图形的方法
        public abstract String getShape();
        //显示图形及颜色
        public void display(String color) {
            System.out.println("方块形状:" + getShape() + ",颜色:" + color);
        }
    }
    
    //具体享元角色(图形L)
    public class LBox extends AbstractBox {
        @Override
        public String getShape() {
            return "L";
        }
    }
    
    //具体享元角色(图形Z)
    public class ZBox extends AbstractBox {
        @Override
        public String getShape() {
            return "Z";
        }
    }
    
    //享元工厂 单例
    public class BoxFactory {
        private Map<String, AbstractBox> map;
        private static BoxFactory instance = new BoxFactory();
        private BoxFactory() {
            map = new HashMap<>();
            map.put("L", new LBox());
            map.put("Z", new ZBox());
        }
        public static BoxFactory getInstance() {
            return instance;
        }
        public AbstractBox getShape(String name) {
            return map.get(name);
        }
    }
    
    public class Test {
        public static void main(String[] args) {
            AbstractBox box1 = BoxFactory.getInstance().getShape("L");
            box1.display("绿色");
            AbstractBox box2 = BoxFactory.getInstance().getShape("Z");
            box2.display("黄色");
            AbstractBox box3 = BoxFactory.getInstance().getShape("Z");
            box3.display("红色");
            //享元模式对图形对象进行了共享
            System.out.println(box2==box3);
        }
    }
    
    输出结果:
    image.png

    从输出结果可以得出box2和box3是同一个对象,享元模式对图像进行了共享,将颜色部分外部化。

    享元模式优缺点:

    优点:
    1、极大减少内存中相似或相同对象数量,节约系统资源,提高系统性能
    2、享元模式中的外部状态相对独立,且不影响内部状态
    缺点:
    为了使对象可以共享,需要将享元对象的部分状态外部化,分离内部状态和外部状态,使程序逻辑复杂

    使用场景:

    1、一个系统有大量相同或者相似的对象,造成内存的大量耗费
    2、对象的大部分状态都可以外部化,可以将这些外部状态传入对象中
    3、使用享元模式需要维护一个存储享元对象的享元池,而这需要耗费一定的系统资源。因此,应该在需要多次重复使用享元对象时才值得使用享元模式

    扩展知识:

    享元模式就是所谓的池化的思想,数据库连接池、线程池、JAVA String用的就是享元模式。这里通过源码分析Java Integer类中的享元模式。

    Integer i1 = 127;
    Integer i2 = 127;
    System.out.println(i1==i2);
    Integer i3 = 128;
    Integer i4 = 128;
    System.out.println(i3==i4);
    //输出结果分别是:true  和 false
    

    从输出结果可以得知i1和i2是相同对象,i3和i4是两个不同的对象。
    关键方法 valueOf(int),Integer默认先创建并缓存 -128 到 127之间的Integer对象。当调用valueOf时,如果参数在-128 到 127之间,则从缓存中读取返回,否则创建新的Integer对象。

    关键源码截图如下:

    image.png
    image.png

    相关文章

      网友评论

          本文标题:享元模式-java

          本文链接:https://www.haomeiwen.com/subject/uauylrtx.html