• 设计模式C#实现(十三)——享元模式(蝇量模式)


     

     

    意图

    运用共享技术有效地支持大量细粒度的对象。

    适用性

    当以下情况都成立时使用:

    • 一个程序使用了大量的对象
    • 完全由于使用大量对象造成很大存储开销
    • 对象的大多数状态都可以变为外部状态
    • 如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象
    • 应用程序不依赖对象标识

    结构

    蝇量UML
    以下摘自参考1

    享元模式采用一个共享来避免大量拥有相同内容对象的开销。这种开销最常见、最直观的就是内存的损耗。享元对象能做到共享的关键是区分内蕴状态(Internal State)和外蕴状态(External State)。
      一个内蕴状态是存储在享元对象内部的,并且是不会随环境的改变而有所不同。因此,一个享元可以具有内蕴状态并可以共享。
      一个外蕴状态是随环境的改变而改变的、不可以共享的。享元对象的外蕴状态必须由客户端保存,并在享元对象被创建之后,在需要使用的时候再传入到享元对象内部。外蕴状态不可以影响享元对象的内蕴状态,它们是相互独立的。

    实现

    现在用程序模拟各种果树,假设树龄是果树的外部状态,而果树的种类是果树的内部状态。
    先来实现抽象果树,它有一个方法,这个方法依靠外部状态——树龄

      public abstract class Tree
        {
            protected string Type;
    
            public virtual void PrintDescription(int age)
            {
                Console.WriteLine(Type + ": " + age);
            }
        }
    

    具体的果树,内部状态需要在实例化时传入

      public class ConcreteTree:Tree
        {
            public ConcreteTree(string type)
            {
                Type = type;
            }
        }
    

    果树工厂负责创建和管理享元角色

       public class TreeFactory
        {
            private Dictionary<string, Tree> _trees = new Dictionary<string, Tree>();
    
            public Tree GetTree(string type)//获取对象
            {
                Tree tree;
                var result = _trees.TryGetValue(type, out tree);//查找该类型对象是否存在
                if (!result)
                {
                    tree = new ConcreteTree(type);//不存在则实例化对象
                    _trees.Add(type, tree);
                }
                return tree;
            }
        }
    

    客户类

     class Program
        {
            static void Main(string[] args)
            {
                var factory = new TreeFactory();
                var tree1 = factory.GetTree("AppleTree");
                tree1.PrintDescription(10);
                var tree2 = factory.GetTree("PeerTree");
                tree2.PrintDescription(12);
                var tree3 = factory.GetTree("AppleTree");
                tree3.PrintDescription(8);
                Console.WriteLine(tree1==tree3);
                Console.ReadKey();
            }
        }
    

    运行结果
    运行结果
    从结果看,tree1和tree3是同一个对象实例,因此当我们有大量的同类果树时,只需要维护一个实例对象和一个树龄数组从而节省了存储空间。

    效果

    • 节省存储空间
    • 逻辑比直接维护多个实例复杂

    参考

    1. 《JAVA与模式》之享元模式
    2. 《Head First 设计模式》
    3. 《设计模式》
  • 相关阅读:
    揭秘重度MMORPG手游后台性能优化方案
    算法:贪心、回溯(su)、分治、动态规划,思想简要
    表单提交 curl和浏览器方式
    mysql 聚集索引,非聚集索引,覆盖索引区别。
    虚拟机中的Linux不能上网
    第二篇 界面开发 (Android学习笔记)
    第一篇 入门必备 (Android学习笔记)
    C/C++知识补充 (1)
    向后/向前引用, 零宽断言, 转义, 命名分组
    C/C++知识补充(2) C/C++操作符/运算符的优先级 & 结合性
  • 原文地址:https://www.cnblogs.com/castdream/p/5061454.html
Copyright © 2020-2023  润新知