设计模式--享元模式

↘锁芯ラ 提交于 2020-01-27 07:55:19
  1. 享元模式使用共享技术(开辟一块静态的存储区域,将相似的对象放入该静态区域),实现相同或者相似对象大量细粒度的对象复用,达到共享类或者对象的目的。

  2. 减少了空间复杂度,加大了时间复杂度

  3. 系统使用少量的对象,而这些都比较相似,状态变化小,可以实现对象的多次复用。

  4. 享元模式中两个重要的概念

    1. 内部状态:在享元对象内部不随外界环境改变而改变的共享部分。
    2. 外部状态:随着环境的改变而改变,不能够共享的状态就是外部状态。
  5. 由于享元模式区分了内部状态和外部状态,所以可以通过设置不同的外部状态使得相同的对象具备不同的特性。内部状态存储于享元对象内部,外部状态则应该由客户端来考虑。

  6. 享元模式的UML图

    在这里插入图片描述

  7. Flyweight抽象享元类。ConcreteFlyweight具体享元类,指定内部状态,为内部状态增加存储空间。关心共享部分,代表了内部状态的共享值,共享值要结合FlyweightFactory来看。UnsharedConcreteFlyweight非共享具体享元类,支出那些不需要共享的Flyweight子类。FlyweightFactory享元工厂类,用来创建并管理Flyweight对象,确保合理的共享Flyweight。

  8. 享元模式的核心在于享元工厂类,享元工厂类的作用在于提供一个用于存储享元对象的享元池,用户需要对象时,首相从享元池中获取,如果享元池中不存在,则创建一个新的享元对象给用户,并在享元池中保存该对象。

  9. 享元模式是对象池的一种实现,目的在于尽可能的减少内存的使用量。其实现共享的关键在于内部状态和外部状态,内部可共享,外部不可共享,从而实现高效重用。

  10. 享元模式的代码实现

  11. 新建一个抽象享元类(包含共享的状态和非共享的状态)

    /**
     * 抽象享元类,瓶盖,包含了内部状态(共享的状态)和外部状态(非共享状态)
     */
    public interface BottleCapFlyweight {
        //内部状态
        String getColor();
    
        //外部状态
        String getCode(String different);
    }
    
  12. 创建非共享状态的子类

    /**
     * 不可共享的享元类,关注非共享部分
     */
    public class UnShareConcreteBottleCapFlyweight implements BottleCapFlyweight{
    
        /**
         * 不需要考虑,因为颜色是不可共享部分的代表
         * @return
         */
        @Override
        public String getColor() {
            return null;
        }
    
        /**
         *
         * @param different
         * @return
         */
        @Override
        public String getCode(String different) {
            return different + "制作完成";
        }
    }
    
  13. 创建共享状态的子类,需要包含非共享状态的分布

    /**
     * 共享的享元类,关注类整体,同时引入了非共享部分
     */
    public class ShareConcreteBottleCapFlyweight implements BottleCapFlyweight {
    
        private BottleCapFlyweight bottleCapFlyweight;
        private String color;
    
        public ShareConcreteBottleCapFlyweight(String color, BottleCapFlyweight bottleCapFlyweight) {
            this.color = color;
            this.bottleCapFlyweight = bottleCapFlyweight;
        }
    
        @Override
        public String getColor() {
            return this.color;
        }
    
        /**
         * 虽然ShareConcreteBottleCapFlyweight作为可共享的子类,
         *     但是享元模式最终想要的对象是内部状态加外部状态的一个完整的对象。
         * 外部状态不是可共享的子类考虑考虑的,但最终需要一个完整的对象(外部状态+内部状态),
         *     所以只要将NoShareConcreteBottleCapFlyweight关联进来就可以调用NoShareConcreteBottleCapFlyweight的getCode方法
         * @param different
         * @return
         */
        @Override
        public String getCode(String different) {
            if(null == bottleCapFlyweight){
                return "活动结束,没有二维码";
            }
            return bottleCapFlyweight.getCode(different);
        }
    }
    
  14. 创建factory类(用于存储享元池)

    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * 不是制造工厂,而是提供享元池,存储享元对象
     */
    public class BottleCapFlyweightFactory {
    
        private static Map<String, BottleCapFlyweight> bottleCapMap = new HashMap<>();
    
        //代表的是非共享元素,由于非共享元素可能比较多,所以是有父类进行关联
        BottleCapFlyweight bottleCapFlyweight;
    
        public static BottleCapFlyweight getBottleCapFlyweight(String color, BottleCapFlyweight bottleCapFlyweight){
            BottleCapFlyweight bottleCap = bottleCapMap.get(color);
            if(null != bottleCap){
                return bottleCap;
            }
            bottleCap = new ShareConcreteBottleCapFlyweight(color, bottleCapFlyweight);
            bottleCapMap.put(color, bottleCap);
            return bottleCap;
        }
    
    }
    
  15. 创建测试类

    public class Test {
        public static void main(String[] args) {
            /**
             * 享元模式的两种调用方式之一:简单享元模式,不需要考虑非共享部分
             * 不需要二维码,第二个参数决定了外部状态
             */
            BottleCapFlyweight bottleCapFlyweight2 = BottleCapFlyweightFactory.getBottleCapFlyweight("黄色", null);
            System.out.println("color: "+bottleCapFlyweight2.getColor() + ", code: "+bottleCapFlyweight2.getCode("二维码"));
    
            /**
             * 享元模式的两种调用方式之一:正常享元模式,需要考虑非共享部分
             */
            BottleCapFlyweight bottleCapFlyweight5 = BottleCapFlyweightFactory.getBottleCapFlyweight("红色", new UnShareConcreteBottleCapFlyweight());
            System.out.println("color: "+bottleCapFlyweight5.getColor() + ", code: "+bottleCapFlyweight5.getCode("我的二维码"));
    
        }
    }
    
  16. 享元模式的优点

    1. 极大的减少系统中对象的个数
    2. 由于使用了外部状态,外部状态相对独立,不会影响到内不状态,使得享元模式能够在不同的环境被共享。
  17. 享元模式的缺点

    1. 由于需要区分内部状态和外部状态,是的程序更加复杂了
    2. 为了使对象可以共享,享元模式需要将对象的状态外部化,而读取外部状态使得运行时间变长。
  18. 享元模式的使用场景

    1. 如果一个系统中存在大量的相同或者相似的对象,由于这类对象的大量使用,会造成系统内存的耗费,可以使用享元模式来减少系统中对象的个数。
    2. 对象的大部分状态都可以外部化,可以将这些外部状态传入对象中。
  19. JDK中对享元模式的使用

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!