总目录
前言
假设你有一个机器猫,你要的什么他就给你变什么,其实啊,机器猫肚子里面有个神奇的工厂,你要什么他就给你造什么,然后给你;有一天你和机器猫说,你比较喜欢小米su7,于是机器猫给你变了一个小米su7,第二天你说你喜欢保时捷,于是机器猫又给你变了一个保时捷;第三天你说你还是比较喜欢小米su7,机器猫没办法又重新给你变了一辆su7;第四天你说你喜欢保时捷,机器猫又给你变了个保时捷,就这样一直反反复复...
事情在第10天的晚上发生了转变,机器猫感觉你要的总是那几样东西,还老是重复,还要天天给你重新造,这个太麻烦了;于是他想到了一个改进的办法,那就将凡是已经造的东西,你用完之后就给你保存在肚子里,下次你要用的时候就直接给你,就不要重新去造了;这对于机器猫来说简直省了好多事,对你来说机器猫也变得更高效了,要什么一下子就给你了!
对了,机器猫就是用到了享元模式的核心思想,下面我们就来看看享元模式吧!
1 基础介绍
上面说到的了机器猫的小故事用到了享元模式的思想,而在我们日常的开发过程中,如果我们需要重复使用某个对象的时候,如果我们重复地使用new创建这个对象的话,这样我们在内存就需要多次地去申请内存空间了,这样可能会出现内存使用越来越多的情况,这样的问题是非常严重。如果让我们去解决这个问题肯定会这样想:"既然都是同一个对象,能不能只创建一个对象,然后下次需要创建这个对象的时候,让它直接用已经创建好了的对象就好了"。也就是说让一个对象共享,这就是共享模式的实际应用了!
-
定义:运用共享技术有效地支持大量细粒度的对象。通过共享对象来尽量减少内存使用和对象数量。
-
目的:使用享元模式可以大大减少系统中对象的数量,从而减少了内存的使用。在对象数量较大,且需要相同状态的对象在内存中存在多个实例时,使用享元模式可以提高系统的性能和内存的使用效率。
-
享元模式中的角色:
- 抽象享元角色(Flyweight):此角色是所有的具体享元类的基类,为这些类规定出需要实现的公共接口。那些需要外部状态的操作可以通过调用方法以参数形式传入。
- 具体享元角色(ConcreteFlyweight):实现抽象享元角色所规定的接口。如果有内部状态的话,可以在类内部定义。
- 享元工厂角色(FlyweightFactory):本角色负责创建和管理享元角色。本角色必须保证享元对象可以被系统适当地共享,当一个客户端对象调用一个享元对象的时候,享元工厂角色检查系统中是否已经有一个符合要求的享元对象,如果已经存在,享元工厂角色就提供已存在的享元对象,如果系统中没有一个符合的享元对象的话,享元工厂角色就应当创建一个合适的享元对象。
- 客户端角色(Client):本角色需要存储所有享元对象的外部状态。
-
享元对象的内部状态与外部状态的定义为:
- 内部状态:在享元对象的内部并且不会随着环境的改变而改变的共享部分
- 外部状态:随环境改变而改变的,不可以共享的状态。
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------享元模式的写法