设计模式笔记——享元模式(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)注意实现享元工厂时,只有具体的享元对象不存在于内存时才去新建否则失去享元的意义。

原文地址:https://www.cnblogs.com/Abel-Zhang/p/FlyweightPattern.html