面向对象设计模式_享元模式(Flyweight Pattern)解读

场景:程序需要不断创建大量相似的细粒度对象,会造成严重的内存负载。我们可以选择享元模式解决该问题。

享元抽象:Flyweight 描述享元的抽象结构。它包含内蕴和外蕴部分(别被术语迷惑,这是一种比较深的描述,浅的来说,内蕴就是对象中不变的数据,外蕴反之,在编程时区分两者的区别就可以了,无需刻意在代码中表达这种术语的含义。)

享元:ConcreteFlyweight 可用用来共享的对象实例,我们将享元的按照共享性质分为内蕴(不因环境变化而变的部分),外蕴两部分。内蕴是享元的固有特性,不会变化。外蕴需要享元被调用时由外部设置。

享元池(或叫享元工厂):FlyweightFactory存放享元的地方。

非共享享元:UnsharedFlyweight 与享元都继承自享元抽象,但其不能被共享。其应用在需要将一个享元组合一起使用,并统一设置外蕴的情景。比如为了提高执行速度,将经常重复出现的对象组(其中每个对象也可以是从享元池中共享抽取出来的)封装到一起,从而执行重复的工作。比如说制图中,由几个基本形状组成的复合形状需要经常被提取出来执行绘制操作。

模型图如下:

 

示例:

//在一个任务中客户需要绘制大量的正方形
 //其中这些正方形在填充颜色和尺寸上仅有有限的几个固定值。
 //边长是5,10,15,颜色,红,绿,蓝,这代表客户端需求按边长,颜色分组最多有3*3=9组类似的正方形对象。

//如果每次需要一个正方形对象,其中每个对象关于填充颜色的数据很大,如果都要一一实例化,将会是内存读写,负载不断增大。

 //如果采用享元模式,在享元池中最多存放9种不同内蕴的实例。那么将大大减少内存负载。

//经常会出现一些同样的组合形状被重复绘制
 //为了提高运行效率,可以将这些重复出现的对象封装到一起执行任务

 

 //定义享元抽象Flyweight
    public abstract class Rectangle
    {
        //对象的坐标(属于对象的外蕴部分)
        public float PointX { get; set; }
        public float PointY { get; set; }

        //内蕴
        public string Color { get; set; }
        //边长
        public float Width { get; set; }
        //设置外蕴
        public abstract void SetStart(float x,float y);
    } 

 //定义具体享元
    public class RedRectangle:Rectangle
    {
        public RedRectangle()
        {
            this.Color = "Red";
        }

        public override void SetStart(float x,float y)
        {
            this.PointX = x;
            this.PointY = y;
        }
    }
    public class GreenRectangle : Rectangle
    {
        public GreenRectangle()
        {
            this.Color = "Green";
        }

        public override void SetStart(float x,float y)
        {
            this.PointX = x;this.PointY = y;
        }
    }
    public class BlueRectangle : Rectangle
    {
        public BlueRectangle()
        {
            this.Color = "Blue";
        }

        public override void SetStart(float x,float y)
        {
            this.PointX = x;
            this.PointY = y;
        }
    }

 //定义一个非共享元
    public class UshareRectangle : Rectangle
    {
        public List<Rectangle> Rectangles { get; set; }
        public UshareRectangle()
        {

        }

        public override void SetStart(float x, float y)
        {
            for(int i=0;i<Rectangles.Count;i++)
            {
                Rectangles[0].PointX = x+i*15;
                Rectangles[0].PointX = y + i * 15;
            }
           
        }
    }

 //定义享元池
    public class FlyweightPool
    {
        public Hashtable Pool { get; set; }


    }

//定义一个客户端
    public static class Client
    {
        public static void DrawRectangle(Rectangle rectangle,float x,float y)
        {
            rectangle.SetStart(x, y);
            Console.WriteLine("您在({0},{1})处画了一个边长为{2}的{3}正方形"
                ,rectangle.PointX,rectangle.PointY,rectangle.Width,rectangle.Color);
        }
    }



//测试代码

public class Test
    {
       private  FlyweightPool pool = new FlyweightPool() { Pool = new Hashtable() };//定义一个工厂实例
//在平台上画上2000个随机指定类型的正方形
public void Test1() { //画图开始 //在指定的2000个位置画总共2000个正方形 float[][] position = new float[2000][]; for (int i = 0; i < 2000; i++) { position[i] = new float[2]; position[i][0] = i * 15; position[i][1] = i * 15; } Random random = new Random(1); for (int i = 0; i < 2000; i++) { switch (random.Next(8)) { case 0: if (pool.Pool["r5"]==null) { pool.Pool.Add("r5", new RedRectangle() { Color = "Red", Width = 5 }); } Client.DrawRectangle((Rectangle)pool.Pool["r5"],position[i][0],position[i][1]); break; case 1: if (pool.Pool["r10"] == null) { pool.Pool.Add("r10", new RedRectangle() { Color = "Red", Width = 10 }); } Client.DrawRectangle((Rectangle)pool.Pool["r10"], position[i][0], position[i][1]); break; case 2: if (pool.Pool["r15"] == null) { pool.Pool.Add("r15", new RedRectangle() { Color = "Red", Width = 15 }); } Client.DrawRectangle((Rectangle)pool.Pool["r15"], position[i][0], position[i][1]); break; case 3: if (pool.Pool["g5"] == null) { pool.Pool.Add("g5", new GreenRectangle() { Color = "Green", Width = 5 }); } Client.DrawRectangle((Rectangle)pool.Pool["g5"], position[i][0], position[i][1]); break; case 4: if (pool.Pool["g10"] == null) { pool.Pool.Add("g10", new GreenRectangle() { Color = "Green", Width = 10 }); } Client.DrawRectangle((Rectangle)pool.Pool["g10"], position[i][0], position[i][1]); break; case 5: if (pool.Pool["g15"] == null) { pool.Pool.Add("g15", new GreenRectangle() { Color = "Green", Width = 15 }); } Client.DrawRectangle((Rectangle)pool.Pool["g15"], position[i][0], position[i][1]); break; case 6: if (pool.Pool["b5"] == null) { pool.Pool.Add("b5", new BlueRectangle() { Color = "Blue", Width = 5 }); } Client.DrawRectangle((Rectangle)pool.Pool["b5"], position[i][0], position[i][1]); break; case 7: if (pool.Pool["b10"] == null) { pool.Pool.Add("b10", new BlueRectangle() { Color = "Blue", Width = 10 }); } Client.DrawRectangle((Rectangle)pool.Pool["b10"], position[i][0], position[i][1]); break; case 8: if (pool.Pool["b15"] == null) { pool.Pool.Add("b15", new BlueRectangle() { Color = "Blue", Width = 15 }); } Client.DrawRectangle((Rectangle)pool.Pool["b15"], position[i][0], position[i][1]); break; default: break; } } } //重复绘制图形组合 public void Test2() { //重复绘制某组合 UshareRectangle urs = new UshareRectangle(); if (pool.Pool["r5"] == null) { pool.Pool.Add("r5", new RedRectangle() { Color = "Red", Width = 5 }); } urs.Rectangles.Add((Rectangle)pool.Pool["r5"]); if (pool.Pool["r10"] == null) { pool.Pool.Add("r10", new RedRectangle() { Color = "Red", Width = 5 }); } urs.Rectangles.Add((Rectangle)pool.Pool["r10"]); int x = 0, y = 0; for (int i = 0; i < 20; i++) { foreach (Rectangle r in urs.Rectangles) { Client.DrawRectangle(r, x,y); x += 15;y += 15; } } } }

 

posted @ 2018-03-19 16:23  joelylee  阅读(533)  评论(0编辑  收藏  举报