C# 设计模式之享元模式

总目录


前言

假设你有一个机器猫,你要的什么他就给你变什么,其实啊,机器猫肚子里面有个神奇的工厂,你要什么他就给你造什么,然后给你;有一天你和机器猫说,你比较喜欢小米su7,于是机器猫给你变了一个小米su7,第二天你说你喜欢保时捷,于是机器猫又给你变了一个保时捷;第三天你说你还是比较喜欢小米su7,机器猫没办法又重新给你变了一辆su7;第四天你说你喜欢保时捷,机器猫又给你变了个保时捷,就这样一直反反复复...

事情在第10天的晚上发生了转变,机器猫感觉你要的总是那几样东西,还老是重复,还要天天给你重新造,这个太麻烦了;于是他想到了一个改进的办法,那就将凡是已经造的东西,你用完之后就给你保存在肚子里,下次你要用的时候就直接给你,就不要重新去造了;这对于机器猫来说简直省了好多事,对你来说机器猫也变得更高效了,要什么一下子就给你了!

对了,机器猫就是用到了享元模式的核心思想,下面我们就来看看享元模式吧!


1 基础介绍

上面说到的了机器猫的小故事用到了享元模式的思想,而在我们日常的开发过程中,如果我们需要重复使用某个对象的时候,如果我们重复地使用new创建这个对象的话,这样我们在内存就需要多次地去申请内存空间了,这样可能会出现内存使用越来越多的情况,这样的问题是非常严重。如果让我们去解决这个问题肯定会这样想:"既然都是同一个对象,能不能只创建一个对象,然后下次需要创建这个对象的时候,让它直接用已经创建好了的对象就好了"。也就是说让一个对象共享,这就是共享模式的实际应用了!

  1. 定义:运用共享技术有效地支持大量细粒度的对象。通过共享对象来尽量减少内存使用和对象数量。

  2. 目的:使用享元模式可以大大减少系统中对象的数量,从而减少了内存的使用。在对象数量较大,且需要相同状态的对象在内存中存在多个实例时,使用享元模式可以提高系统的性能和内存的使用效率。

  3. 享元模式中的角色:

    • 抽象享元角色(Flyweight):此角色是所有的具体享元类的基类,为这些类规定出需要实现的公共接口。那些需要外部状态的操作可以通过调用方法以参数形式传入。
    • 具体享元角色(ConcreteFlyweight):实现抽象享元角色所规定的接口。如果有内部状态的话,可以在类内部定义。
    • 享元工厂角色(FlyweightFactory):本角色负责创建和管理享元角色。本角色必须保证享元对象可以被系统适当地共享,当一个客户端对象调用一个享元对象的时候,享元工厂角色检查系统中是否已经有一个符合要求的享元对象,如果已经存在,享元工厂角色就提供已存在的享元对象,如果系统中没有一个符合的享元对象的话,享元工厂角色就应当创建一个合适的享元对象。
    • 客户端角色(Client):本角色需要存储所有享元对象的外部状态。
  4. 享元对象的内部状态与外部状态的定义为:

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

2 使用场景

享元模式常用于大规模创建相同或相似对象的场景,例如线程池、缓存池以及字符串池等。此外,它还可以用于减少系统中相同状态对象的数量,提高系统性能和内存使用效率。

3 实现方式

下面我们以一个绘制不同颜色的图形为案例说明:

1 定义图形的颜色相关对象

csharp 复制代码
    public abstract class AbstractColor
    {
        public abstract string Show();
    }

    public class Red : AbstractColor
    {
        public override string Show()
        {
            return "red";
        }
    }

    public class Green : AbstractColor
    {
        public override string Show()
        {
            return "green";
        }
    }

2 定义享元对象

csharp 复制代码
    // 定义抽象享元对象
    public abstract class AbstractShape
    {
        public string Name { get; set; }

        public AbstractShape(string name)
        {
            Name = name;
        }
        //定义一个子类必须实现的方法
        public abstract void Draw();

        public AbstractColor ShapeColor{ get; set; }

    }

    // 实现具体的享元对象类
    public class Circle : AbstractShape
    {
        public Circle(string name) : base(name)
        {
        }

        public override void Draw()
        {
            Console.WriteLine("Drawing a " + ShapeColor.Show() + " circle.");
        }
    }


    // 实现具体的享元对象类
    public class Line : AbstractShape
    {
        public Line(string name) : base(name)
        {
        }

        public override void Draw()
        {
            Console.WriteLine("Drawing a " + ShapeColor.Show() + " line.");
        }
    }

3 定义享元工厂类,负责创建和管理享元对象

csharp 复制代码
 // 定义享元工厂类
    public class ShapeFactory
    {
        private Dictionary<string, AbstractShape> shapeDictionary = new Dictionary<string, AbstractShape>();

        public AbstractShape GetShape(string name,AbstractColor color,string shapeType)
        {
            // 如果已经有相同名称的 形状 则 直接返回该对象
            if (shapeDictionary.ContainsKey(name))
            {
                return shapeDictionary[name];
            }

            // 否则创建新的颜色的形状 并将其放入字典中
            AbstractShape shape = null;
            if (shapeType == "Circle")
            {
                shape = new Circle(name);
            }
            else if (shapeType=="Line")
            {
                shape=new Line(name);
            }
            shape.ShapeColor = color;

            shapeDictionary.Add(name, shape);
            return shape;
        }
    }

4 客户端调用

csharp 复制代码
        static void Main(string[] args)
        {
            ShapeFactory shapeFactory = new ShapeFactory();

            // 获取红色线条
            AbstractShape redCircle = shapeFactory.GetShape("RedLine",new Red(),"Line");
            redCircle.Draw();

            // 获取绿色圆形
            AbstractShape greenCircle = shapeFactory.GetShape("GreenCircle", new Green(), "Circle");
            greenCircle.Draw();

            // 再次获取红色线条
            AbstractShape redCircle2 = shapeFactory.GetShape("RedLine", new Red(), "Line");
            redCircle2.Draw();
           
            Console.ReadKey();
        }

4 优缺点分析

  • 优点
    • 降低了系统中对象的数量,提高系统性能和内存使用效率,同时降低代码复杂度
    • 享元模式由于使用了外部状态,外部状态相对独立,不会影响到内部状态,所以享元模式使得享元对象能够在不同的环境被共享。
  • 缺点
    • 为了使对象可以共享,需要将享元对象的部分状态外部化,分离内部状态和外部状态,这使得程序的逻辑更复杂,使系统复杂化。

结语

希望以上内容可以帮助到大家,如文中有不对之处,还请批评指正。


参考资料:
c#享元模式详解
C#设计模式(12)------享元模式(Flyweight Pattern)
C#设计模式之十一享元模式(Flyweight Pattern)【结构型】
C#设计模式11------享元模式的写法

相关推荐
bluefox19792 小时前
使用 Oracle.DataAccess.Client 驱动 和 OleDB 调用Oracle 函数的区别
开发语言·c#
鲤籽鲲3 小时前
C# MethodTimer.Fody 使用详解
开发语言·c#·mfc
工业3D_大熊4 小时前
3D可视化引擎HOOPS Luminate场景图详解:形状的创建、销毁与管理
java·c++·3d·docker·c#·制造·数据可视化
yngsqq4 小时前
c#使用高版本8.0步骤
java·前端·c#
小白不太白9504 小时前
设计模式之 模板方法模式
java·设计模式·模板方法模式
色空大师4 小时前
23种设计模式
java·开发语言·设计模式
闲人一枚(学习中)5 小时前
设计模式-创建型-建造者模式
java·设计模式·建造者模式
博风5 小时前
设计模式:6、装饰模式(包装器)
设计模式
A_cot5 小时前
理解设计模式与 UML 类图:构建稳健软件架构的基石
microsoft·设计模式·简单工厂模式·工厂方法模式·uml
君败红颜5 小时前
设计模式之创建模式篇
设计模式