• 面向对象编程思想-享元模式


    一、引言

    在软件开发中,当我们需要重复使用某个对象时,如果重复使用new创建这个对象,内存就需要多次去申请内存空间,这样可能造成资源浪费甚至内存溢出等问题。。。下面请看我们我们今天学习的享元模式是如何解决这个问题的

    二、享元模式的结构

    借用下大话设计模式中的图,嘿嘿。。。

    三、享元模式

    定义:运用共享技术有效的支持大量细粒度的对象。享元模式可以避免大量非常相似类的开销。在程序设计中,有时需要生成大量细粒度的类实例来表示数据。如果能发现这些实例除了几个参数外基本上都是相同的,这时可以使用享元模式大幅度的减少需要实例化的类的数量。如果能把那些参数移到类实例的外面,在方法调用时将它们传递进来,就可以通过共享大幅度地减少单个实例的数目。

    内部状态:在享元对象的内部并且不会随着环境改变而改变的共享部分

    外部状态:随环境的改变而改变不可以共享的状态

    介绍了享元模式的定义,下面先看一下它在.NET中的应用

                string a = "abc";
                string b = "abc";
                Console.WriteLine(ReferenceEquals(a,b));            
    View Code

    分析:a和b都指向常量池中的同一个字符串常量“abc”,这样设计避免了在创建N多相同对象所产生的不必要的大量的资源消耗。

    String对象是不可变的,字符串一经创建便不能更改。不可变意味着操作或访问字符串时不会发生线程同步的问题。CLR可通过一个String对象共享多个完全一致的String内容。这样就能减少系统中字符串的数量,从而节约内存,也称作“字符串留用”。

    下面看一下电脑上下围棋的demo:

        //抽象享元类 提供具体享元类具有的方法
        abstract class Flyweight
        {
            public abstract void Operation(int extrinsicstate);
        }
        //具体的享元类对象 (我们不是把每个棋子设计成单独的类了,而是把共享的颜色作为享元对象的内部状态)
        class ConcreteFlyweight:Flyweight
        {
            //内部状态
            private string intrinsicstate;
            public ConcreteFlyweight(string innerState)
            {
                this.intrinsicstate = innerState;
            }
           /// <summary>
           /// 享元类实例方法
           /// </summary>
           /// <param name="extrinsicstate">外部状态</param>
            public override void Operation(int extrinsicstate)
            {
                Console.WriteLine("具体实现类intrinsicstate:{0},extrinsicstate:{1}", intrinsicstate, extrinsicstate);
            }
        }
        class FlyweightFactory
        {
            public Hashtable hasFactory = new Hashtable();
    
            public Flyweight GetFlyweight(string key)
            {
                if (!hasFactory.Contains(key))
                {
                    hasFactory.Add(key, new ConcreteFlyweight(key));
                }
                return (Flyweight)hasFactory[key];
            }
        }
        class Program
        {
            static void Main(string[] args)
            {
                //定义外部状态 如棋子的位置坐标
                int extrinsicstate = 10;
                //初始化工厂
                FlyweightFactory flyweightFactory = new FlyweightFactory();
                flyweightFactory.GetFlyweight("白棋").Operation(--extrinsicstate);
    
                flyweightFactory.GetFlyweight("黑棋").Operation(--extrinsicstate);
    
                flyweightFactory.GetFlyweight("白棋").Operation(--extrinsicstate);
    
                Console.Read();
            }
        }
    View Code

    分析:围棋有黑白两个颜色,这个通常是不会变的,所以颜色应该是棋子的内部状态。对弈时各个棋子之间的差别主要是位置不同,所以方位坐标应该是棋子的外部状态

    围棋有361个空位可以放棋子,常规的面向对象方式编程,一盘棋要产生2、3百个对象,一台服务器很难支持更多的玩家玩围棋游戏了,毕竟内存空间是有限的,如果用享元模式来处理棋子,将棋子对象减少到只有两个实例,将可以节约大量的不必要资源消耗

    优点:降低系统中对象的数量,从而降低系统中细粒度对象给内存带来的压力

    缺点:

    1.为了使对象可以共享,需要将一些状态外部化,使得程序复杂化

    2.享元模式将享元对象的状态外部化,而读取外部状态使得运行时间稍微变长

    使用场景:

    1.系统中有大量对象,这些对象耗费大量内存

    2.这些对象中的状态大部分都可以被外部化

    3.这些对象可以按照内部状态分成很多的组,当把外部对象从对象中剔除时,这些对象可以仅用一个对象代替

    4.系统不依赖于这些对象的身份,这些对象是不可分辨的

    关于享元模式的学习就到此结束了,希望能够帮到你,若有不足,欢迎斧正,感谢您的阅读。

  • 相关阅读:
    JavaScript 按位与和逻辑与
    JavaScript跨域问题
    前端-知识+能力感触
    堆&堆排序
    Java中的数据类型和引用
    基础算法之选择排序
    基于TCP协议的网络通讯流程
    Java基础之封装
    个人主页
    算法基础之希尔排序
  • 原文地址:https://www.cnblogs.com/jdzhang/p/7245187.html
Copyright © 2020-2023  润新知