zoukankan      html  css  js  c++  java
  • 设计模式笔记——享元模式(Flyweight Pattern)

    一、概述

    在软件开发有时需要创建大量细粒度的对象(比如:文档处理系统就可能需要创建成千上万的字符对象)。但如果new一个新的字符对象就会分配内存空间,那么在系统运行时就会耗费大量的内存资源。如何在保留面向对象操作方式优点的同时避免创建大量的对象呢?这就到了享元模式发挥作用的时候了。

    二、享元模式

    享元模式运用共享技术有效地支持大量细粒度的对象。例如可以对文档处理系统创建共享池(内存),在共享池中建立字母和代码的对应关系,这样就可以用共享池中的对象解决需要创建大量对象的问题。其结构图如下:

    Flyweight定义了享元接口,外部对象通过这个接口来访问具体的享元对象。

    ConcreteFlyweight实现Flyweight接口,定义了具体的享元对象,并保存享元对象的内部状态。该享元对象是可共享的。

    UnsharedConcreteFlyweight实现Flyweight接口,定义了不用于共享的享元对象。

    FlyweightFactory创建并管理享元对象。

    Client保存对享元接口的引用,通过该引用有效的使用具体的享元对象。

    三、示例(由于我们做成动态创建对象形式所有不用抽象类)

      我们实现一个简单的文本编辑系统。

    1.创建字型类:

     public  class Character
        {
            public Color Color { get; set; }
            private char alphabet;
    
            public Character(char c)
            {
                this.alphabet = c;
                this.Color = Color.Black;
            }
    
            public Character()
            {
    
            }
            public char Alphabet
            {
                get { return alphabet; }
                private set { alphabet = value; }
            }
    
        }
    

    2. 创建字型工厂类:

    public class CharacterFactory
        {
            private static Dictionary<char, Character> _character=new Dictionary<char,Character>();
            private static CharacterFactory glyphsfactory = new CharacterFactory();
    
            public CharacterFactory()
            {
    
            }
            public static CharacterFactory getInstance()
            {
                return glyphsfactory;
            }
            public Character GetCharacter(char c)
            {
    
                if (_character == null || !_character.ContainsKey(c))
                {
                    Character character = new Character(c);
                    _character.Add(c, character);
                }
    
                return _character[c];
            }
    
        }
    

    3.创建坐标类:

    public class Position
        {
            private int x;
    
            public int X
            {
                get { return x; }
                private set { x = value; }
            }
    
            private int y;
    
            public int Y
            {
                get { return y; }
                private set { y = value; }
            }
    
            public Position(int x, int y)
            {
                this.x = x;
                this.y = y;
    
            }
        }

    4.创建坐标工厂类:

    public class PositionFactory
        {
            private static PositionFactory positionFactory = new PositionFactory();
            private Hashtable positionTable = new Hashtable();
            static PositionFactory()
            {
    
            }
            public static PositionFactory getInstance()
            {
                return positionFactory;
            }
            public Position GetPosition(int X, int Y)
            {
                string key = X.ToString() + "|" + Y.ToString();
                if (positionTable == null || !positionTable.ContainsKey(key))
                {
                    Position position = new Position(X, Y);
                    positionTable.Add(key, position);
                }
    
                return (Position)positionTable[key]; 
            }
    
        }
    

    5. 看一下具体调用(测试代码略):

     public class Program
        {
            static void Main(string[] args)
            {
                string Data = "Do not dwell in the past, do not dream  of the future, concentrate the mind on  the present moment.";
                char[] characters = new char[120];
                characters = Data.ToCharArray();
                CharacterFactory characterFactory = CharacterFactory.getInstance();
                PositionFactory positionFactory = PositionFactory.getInstance();
                Character character;
                Position position;
                for (int i = 0; i < 3; i++)
                {
                    for (int j = 0; j < 40; j++)
                    {
                        if ((j + (i * 40)) <= 98)
                        {
                            character = characterFactory.GetCharacter(characters[j + (i * 40)]);
                            position = positionFactory.GetPosition(i, j);
                            setColor(character, i, j);
                            Console.WriteLine("{0}[{1}]({2},{3})", character.Alphabet, character.Color.Name.ToString(), position.X, position.Y);
                        }
                    }
                }
                Console.ReadKey();
            }
    
            private static void setColor(Character character, int i, int j)
            {
                if (j + (i * 40) >= 7 && j + (i * 40) <= 11)
                {
                    character.Color = Color.Red;
                }
                else if (j + (i * 40) >= 20 && j + (i * 40) <= 23)
                {
                    character.Color = Color.Orange;
                }
                else if (j + (i * 40) >= 33 && j + (i * 40) <= 37)
                {
                    character.Color = Color.Yellow;
                }
                else if (j + (i * 40) >= 47 && j + (i * 40) <= 52)
                {
                    character.Color = Color.Green;
                }
                else if (j + (i * 40) >= 55 && j + (i * 40) <= 65)
                {
                    character.Color = Color.Blue;
                }
                else if (j + (i * 40) >= 71 && j + (i * 40) <= 74)
                {
                    character.Color = Color.Indigo;
                }
                else if (j + (i * 40) >= 92 && j + (i * 40) <= 97)
                {
                    character.Color = Color.Violet;
                }
                else
                {
                    character.Color = Color.Black;
                }
            } 
        }
    

    6.问题总结:

    1)Ilist插入引用对象问题:在测试代码中将字型对象插入到Ilist<character>中出现字型对象color属性测试不通过,原因是引用类型是以地址形式插入Ilist<character>中,当相同字符的字型对象先后插入时先插入的color属性会被覆盖。

    2)各位匠友可以试着把工厂类抽象,做到充分解耦。

    3)注意实现享元工厂时,只有具体的享元对象不存在于内存时才去新建否则失去享元的意义。

  • 相关阅读:
    第五周总结
    构建之法阅读笔记02
    第四周总结
    使用HttpClient+Json解析器爬取数据并存入数据库
    构建之法阅读笔记01
    使用Echarts+Javaweb可视化数据库中数据
    Oracle自我补充之trunc()函数使用介绍
    Oracle自我补充之OVER()函数介绍
    SpringMVC详细示例实战教程(较全开发教程)
    eclipse逆向生成hibernate的实体类(注解和配置文件)
  • 原文地址:https://www.cnblogs.com/Abel-Zhang/p/FlyweightPattern.html
Copyright © 2011-2022 走看看