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

    定义

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

    适用场景:

    • 应用于系统底层开发。以解决系统性能问题
    • 系统有大量相似对象,需要缓冲池场景

    具体场景

    享元模式主要包含三种角色:

    • 抽象享元角色(IFlyweight):享元对象抽象基类或者接口,同时定义出对象的外部状态和内部状态的接口或实现。
    • 具体享元角色:实现抽象享元角色,该角色的内部状态处理应该与环境无关,不会出现一个操作改变内部状态,同时改变外部状态的情况。
    • 享元工厂:负责管理享元对象池和创建享元对象。

    以英雄联盟兵线为例:有四种小兵,前排兵,后排兵,炮车,超级兵,每个兵种都有自己的颜色(忽略因时间变化等级升高的影响和大龙buff加持的影响等等),可以用享元模式简单实现一下前排兵,后排兵的创建(跑车和超级兵省略)。

    image-20201227205856586

    小兵接口

    
    public interface Minion {
        String getType();
        String getColour();
        default void attack(){
            System.out.println(getColour()+"色方的"+getType()+"正在攻击....");
        }
    }
    

    近战兵:

    //近战兵
    public class MeleeMinion implements Minion{
    
        private String colour;
    
        MeleeMinion(String colour) {
            this.colour = colour;
        }
    
        @Override
        public String getType() {
            return "近战兵";
        }
    
        @Override
        public String getColour() {
            return colour;
        }
    }
    

    远程兵:

    //远程兵
    public class CasterMinion implements Minion{
    
        private String colour;
    
        CasterMinion(String colour) {
            this.colour = colour;
        }
    
        @Override
        public String getType() {
            return "远程兵";
        }
    
        @Override
        public String getColour() {
            return this.colour;
        }
    
    }
    

    享元工厂:

    class MinionFactory {
    
        private static Map<String, Minion> minionPool = new ConcurrentHashMap<>();
    
        //因为内部状态的不变性,所以缓存起来作为主键
        static Minion getMinion(String type, String colour){
            Minion minion;
            if("远程兵".equals(type)){
                if(!minionPool.containsKey(colour)){
                    minion = new CasterMinion(colour);
                    minionPool.put(colour,minion);
                }
            }else if("近战兵".equals(type)){
                if(!minionPool.containsKey(colour)){
                    minion = new MeleeMinion(colour);
                    minionPool.put(colour,minion);
                }
            }
            minion = minionPool.get(colour);
            return minion;
        }
    }
    

    测试:

    public class Test {
        public static void main(String[] args) {
            Minion minion = MinionFactory.getMinion("近战兵", "蓝");
            minion.attack();
            Minion minion2 = MinionFactory.getMinion("近战兵", "蓝");
            minion2.attack();
    
    
            System.out.println(minion == minion2);
    
            Minion minion3 = MinionFactory.getMinion("远程兵", "红");
            minion3.attack();
        }
    }
    

    image-20201227212136992

    uml类图:

    image-20201227212234985

    Integer(Long)中的享元模式

    先测试以下代码:

        public static void main(String[] args) {
            Integer a = 100;
            Integer b = 100;
            System.out.println(a==b);
    
            Integer c = 200;
            Integer d = 200;
            System.out.println(c==d);
        }
    

    image-20201227212453028

    一个为true,一个为false???是不是意想不到。

    打上断点,调试:

    image-20201227212917521

    可以得出,a和b是同一个对象,c和d不是同一个对象,进入Integer源代码,我们可以注意到这样一段代码:

        /**
         * Returns an {@code Integer} instance representing the specified
         * {@code int} value.  If a new {@code Integer} instance is not
         * required, this method should generally be used in preference to
         * the constructor {@link #Integer(int)}, as this method is likely
         * to yield significantly better space and time performance by
         * caching frequently requested values.
         *
         * This method will always cache values in the range -128 to 127,
         * inclusive, and may cache other values outside of this range.
         *
         * @param  i an {@code int} value.
         * @return an {@code Integer} instance representing {@code i}.
         * @since  1.5
         */
        public static Integer valueOf(int i) {
            if (i >= IntegerCache.low && i <= IntegerCache.high)
                return IntegerCache.cache[i + (-IntegerCache.low)];
            return new Integer(i);
        }
    

    Integer的valueOf方法:当值大于等于low或者小于等于high时会调用IntegerCache.cache()方法,否则直接new一个新的Integer,我们继续看IntegerCache的源码:

    image-20201227214053541

    实际上,jdk中的Long类也有这样的处理。

    IntegerCache内部类上有这样的注释

        /**
         * Cache to support the object identity semantics of autoboxing for values between
         * -128 and 127 (inclusive) as required by JLS.
         *
         * The cache is initialized on first usage.  The size of the cache
         * may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
         * During VM initialization, java.lang.Integer.IntegerCache.high property
         * may be set and saved in the private system properties in the
         * sun.misc.VM class.
         */
    

    大致意思我们可以通过设置AutoBoxCacheMax这个参数来控制包装类的最大缓存大小。

    我们设置上参数,再运行

    -XX:AutoBoxCacheMax=300
    

    image-20201227214812340

    image-20201227214848425

  • 相关阅读:
    微软面试100 题题解
    二元查找树转变成排序的双向链表(树)
    筆試
    PE注入
    内核网络通信
    哈哈哈
    OpenCV 学习
    第一次研究VM程序中的爆破点笔记
    SE2.3.4各试用限制调试笔记
    破解相关书籍
  • 原文地址:https://www.cnblogs.com/wwjj4811/p/14198907.html
Copyright © 2011-2022 走看看