zoukankan      html  css  js  c++  java
  • Java设计模式——享元模式

    概述

    在有大量对象时,有可能会造成内存溢出,我们把其中共同的部分抽象出来,如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建。


    版权说明

    著作权归作者所有。
    商业转载请联系作者获得授权,非商业转载请注明出处。
    本文作者:Coding-Naga
    发表日期: 2016年4月25日
    本文链接:http://blog.csdn.net/lemon_tree12138/article/details/51241598
    来源:CSDN
    更多内容:分类 >> 设计模式


    目录


    享元模式

    定义

    享元模式是一种结构型模式,运用共享技术有效地支持大量细粒度的对象。


    单纯享元模式

    在享元模式中,就其定义我们可以构建出单纯的享元模式。下图是单纯享元模式的类图:
    这里写图片描述

    在单纯的享元模式中,需要给出一个抽象接口,以规定出所有具体享元角色需要实现的方法。实现如下:
    Flyweight.java

    public interface Flyweight {
        public void operation(String state);
    }

    对于享元部分,ConcreteFlyweight 必须是可共享的,它保存的任何状态都必须是内部(intrinsic),ConcreteFlyweight 必须和它的应用环境场合无关。比如字符串 “Hello” 就无需关心使用它的场合,它是一个不可变的对象。
    ConcreteFlyweight.java

    public class ConcreteFlyweight implements Flyweight {
    
        private String intrinsicState = null;
    
        /**
         * 构造函数 内蕴状态作为参数传入
         */
        public ConcreteFlyweight(String _intrinsicState) {
            this.intrinsicState = _intrinsicState;
        }
    
        /**
         * 外蕴状态作为参数传入方法中 改变方法的行为 但是并不改变对象的内蕴状态
         */
        @Override
        public void operation(String extrinsicState) {
            System.out.println("内蕴状态:" + intrinsicState);
            System.out.println("外蕴状态:" + extrinsicState);
        }
    
    }

    在享元模式中,有一个至关重要的模块就是工厂模块了。在 Flyweight Factory 里维护了一个 Flyweight 池(存放内部状态),Flyweight Factory 就是通过这个 Flyweight 池对整个享元模式进行控制。
    FlyweightFactory.java

    public class FlyweightFactory {
    
        private Map<Integer, Flyweight> labels = new HashMap<Integer, Flyweight>();
    
        public Flyweight factory(String intrinsicState) {
    
            int hashCode = intrinsicState.hashCode();
    
            Flyweight fly = labels.get(hashCode);
    
            if (fly == null) {
                fly = new ConcreteFlyweight(intrinsicState);
                labels.put(hashCode, fly);
            }
    
            return fly;
        }
    }

    在上面的工厂模块中可以看到,FlyweightFactory 实际上是起到了一个过滤筛选的功能,过滤重复的对象,缓存新对象。


    不共享的享元模式

    与共享的享元对象相对的就是不共享的享元对象。关于不共享的享元对象,可能你会有一些疑问,既然不共享,为何还要包含到享元模式中来呢?这可能是出于完整性的考虑,或是要某些场景下既要使用共享的享元,又要使用不共享的享元吧。关于这一点本人也还没有完全理解,也有可能根本不需要这一个不共享的享元对象吧。下面是不共享的享元类图:
    这里写图片描述

    不共享的享元实现与 ConcreteFlyweight 无异。如下:
    UnsharedConcreteFlyweight.java

    public class UnsharedConcreteFlyweight implements Flyweight {
    
        private String intrinsicState = null;
    
        public UnsharedConcreteFlyweight(String _intrinsicState) {
            this.intrinsicState = _intrinsicState;
        }
    
        @Override
        public void operation(String extrinsicState) {
            System.out.println("内蕴状态:" + intrinsicState);
            System.out.println("外蕴状态:" + extrinsicState);
        }
    }

    下面是对单纯的享元与不共享的享元进行测试的代码。
    Client.java

    public class Client {
    
        public static void main(String[] args) {
            FlyweightFactory factory = new FlyweightFactory();
    
            Flyweight fly1 = factory.factory("Hello");
            fly1.operation("ExtrinsicState-1");
    
            Flyweight fly2 = factory.factory("DesignPattern");
            fly2.operation("ExtrinsicState-2");
    
            Flyweight fly3 = factory.factory("Flyweight");
            fly3.operation("ExtrinsicState-3");
    
            Flyweight fly4 = factory.factory("Hello");
            fly4.operation("ExtrinsicState-4");
    
            System.out.println("fly1 == fly2 ? " + (fly1 == fly2));
            System.out.println("fly1 == fly3 ? " + (fly1 == fly3));
            System.out.println("fly1 == fly4 ? " + (fly1 == fly4));
    
            Flyweight fly5 = new UnsharedConcreteFlyweight("Unshared");
            fly5.operation("ExtrinsicState-5");
        }
    }
    内蕴状态:Hello
    外蕴状态:ExtrinsicState-1
    内蕴状态:DesignPattern
    外蕴状态:ExtrinsicState-2
    内蕴状态:Flyweight
    外蕴状态:ExtrinsicState-3
    内蕴状态:Hello
    外蕴状态:ExtrinsicState-4
    fly1 == fly2 ? false
    fly1 == fly3 ? false
    fly1 == fly4 ? true
    内蕴状态:Unshared
    外蕴状态:ExtrinsicState-5
    

    复合享元模式

    在上面的单纯享元中,所有的享元可以说是在同一个分组里。有时候这样的大集合可能并不能发挥出很好的应用功能,所以引入了复合式的享元模式。下面是复合式享元模式类图:
    这里写图片描述

    复合式享元相当于多个单纯享元的集合。也就是说复合享元相当于对单纯享元进行了一个再分组,在复合享元的每个分组里又是一个独立的单纯享元模式。相关关键代码如下:
    ConcreteCompositeFlyweight.java

    public class ConcreteCompositeFlyweight implements Flyweight {
    
        private Map<Integer, Flyweight> labels = new HashMap<Integer, Flyweight>();
    
        public void add(int key, Flyweight flyweight) {
            labels.put(key, flyweight);
        }
    
        @Override
        public void operation(String extrinsicState) {
            Flyweight flyweight = null;
            for (Object key : labels.keySet()) {
                flyweight = labels.get(key);
                flyweight.operation(extrinsicState);
            }
        }
    }

    对于其构建工厂也需要进行重新设计,如下:
    FlyweightFactory.java

    public class FlyweightFactory {
    
        private Map<Integer, Flyweight> labels = new HashMap<Integer, Flyweight>();
    
        /**
         * 单纯享元工厂
         */
        public Flyweight factory(String intrinsicState) {
             ... ...
             return fly;
        }
    
        /**
         * 复合享元工厂
         */
        public Flyweight compositeFactory(List<String> intrinsicStates) {
            ConcreteCompositeFlyweight flyweight = new ConcreteCompositeFlyweight();
    
            for (String intrinsicState : intrinsicStates) {
                flyweight.add(intrinsicState.hashCode(), factory(intrinsicState));
            }
    
            return flyweight;
        }
    }

    测试类
    Client.java

    public void compositeFlyweight() {
            List<String> intrinsicStates = new ArrayList<String>();
            intrinsicStates.add("Hello");
            intrinsicStates.add("Java");
            intrinsicStates.add("DesignPattern");
            intrinsicStates.add("Flyweight");
    
            FlyweightFactory factory = new FlyweightFactory();
            Flyweight flyweight1 = factory.compositeFactory(intrinsicStates);
            Flyweight flyweight2 = factory.compositeFactory(intrinsicStates);
            System.out.println("flyweight1 == flyweight2 ? " + (flyweight1 == flyweight2));
    
            flyweight1.operation("复合享元-1");
            flyweight2.operation("复合享元-2");
        }
    flyweight1 == flyweight2 ? false
    内蕴状态:Java
    外蕴状态:复合享元-1
    内蕴状态:Flyweight
    外蕴状态:复合享元-1
    内蕴状态:Hello
    外蕴状态:复合享元-1
    内蕴状态:DesignPattern
    外蕴状态:复合享元-1
    内蕴状态:Java
    外蕴状态:复合享元-2
    内蕴状态:Flyweight
    外蕴状态:复合享元-2
    内蕴状态:Hello
    外蕴状态:复合享元-2
    内蕴状态:DesignPattern
    外蕴状态:复合享元-2

    JDK 里的享元模式

    在 JDK 的设计里,也有很享元模式。比如一些常量池的设计(String 常量池、Integer 常量池等等);


    Ref


    GitHub 源码下载


  • 相关阅读:
    ACdream 1224 Robbers (贪心)
    HDU 4320 Arcane Numbers 1 (质因子分解)
    在脚本中重定向输入
    呈现数据
    shell中的for、while、until(二)
    shell中的for、while、until
    C 指针疑虑
    结构化命令
    fdisk -c 0 350 1000 300命令
    PC机上的COM1口和COM2口
  • 原文地址:https://www.cnblogs.com/fengju/p/6335992.html
Copyright © 2011-2022 走看看