了解Flyweight模式

时间:2014-05-15 16:36:40

标签: c# design-patterns flyweight-pattern

  

意图:

     

此模式的目的是使用共享来支持大量数据   具有部分内部状态的对象的共同点   国家的其他部分可能会有所不同。

对象可以通过静态字段共享状态。

使用flyweight模式共享大量对象的内部状态和使用静态字段有什么区别?

flyweight通过其Factory提供的对象池是flyweight真正的全部内容吗?

4 个答案:

答案 0 :(得分:11)

使用静态字段,在任何一个时间点只能使用一个对象实例。使用flyweight模式,您可以同时使用任意数量的不同的实例(每个实例都使用多次)。 flyweight模式的规范示例适用于文本编辑器,您需要为文档中的每个字符实例化一个对象。然后,您不需要在10,000字文档中的每个字符的内存中有一个对象,而是只需要26个对象(假设文档仅使用小写字母),一个用于字母' a',一个用于字母' b'等等,它们会在整个文档中一次又一次地重复使用,每次您需要执行某些功能或操作时需要一个' a'等等。宾语。

编辑:回答以下第一条评论的问题:
因此,由于您需要26个不同的对象,因此创建一个静态的Letter类或单个类不会起作用。如果它是静态的,则无法创建任何实例,因此无论静态值必须适合您使用它的代码中的每个位置。 如果它是单身,那么你当然只有一个对象。每次使用时,每个属性都必须可调整(和调整)。 要将此模式用于字母表中的字母,您必须有26个不同的类,每个字母一个...

此外,该课程的" 部分可以改变"实际上意味着某些字段代表类的每个实例的不同状态。而共同的部分意味着这些公共字段的值对于匹配这些状态值的对象的所有使用是共同的(例如,所有' a' s) ,不适用于班级的每个实例。

再次,使用文本编辑器作为示例。 代码中的每个地方都需要处理一个字符“a'”,首先,转到存储26个字符对象实例的数据结构,并获取'一个'例如, 您首先要修改/更改不同的属性(与其无关的属性作为' a',但可能是它的字体大小,位置,颜色等)以匹配这个特定角色的需要' a'在文件中。
然后,您将利用该对象执行您需要执行的任何操作,然后将其返回到存储结构,以便在下次代码需要' a时使用。

答案 1 :(得分:6)

Flyweight模式用于避免大量非常相似的类的开销。编程中有些情况似乎需要生成大量的小类实例来表示数据。有时,如果您能够识别实例基本上相同,除了一些参数,您可以大大减少需要实例化的不同类的数量。如果您可以将这些变量移出类实例并将其作为方法调用的一部分传递,则可以通过共享它们来大大减少单独实例的数量。

在这种情况下,重要的是要记住,Flyweight是在一个C#只不过是一些功率点图表粗略草图的时代发明的。并且隐含地通过一些这些模式来通知语言的成熟度。 C#包括班级成员......

  

更典型的是使用一些静态声明非静态类   成员,而不是将整个类声明为静态。两种常见用途   静态字段用于保持具有的对象数量   已实例化,或存储必须在所有人之间共享的值   实例

来源C# statics on MSDN

更进一步,WPF技术推广了共享资源,结果通常只是声明性代码。

因此,如果您选择的语言是C#,则可能会建议您考虑针对该语言中已存在的固有属性的Flyweight模式。

答案 2 :(得分:3)

虽然模式及其实现有点主观,但使用静态是一种有效的 - 虽然最简单 - 实现Flyweight的方法。

如果你可以使用静力学,这很棒。否则你可以做一些像你一样的事情......构建flyweight对象的工厂可以分配/引用正确的共享对象。

答案 3 :(得分:1)

这是一个例子,它打印所有的士兵和他们的装饰。

因为并非所有士兵都被装饰,我们正在使用flyweight设计模式。

public class Soldiers
{
  private string[] _soldiers;
  private Dictionary<int, Decoration> _decorations = new Dictionary<int, Decoration>();

  public Soldiers(string[] soldier)
  {
    this._soldiers = soldier;
  }

  public Decoration this[int index]
  {
    get
    {
      Decoration decoration = new Decoration();
      this._decorations.Add(index, decoration);
      return this._decorations[index];
    }
  }

  public override string ToString()
  {
    var soldierList = new List<string>();
    for (var i = 0; i < this._soldiers.Length; i++)
    {
      string soldier = this._soldiers[i];
      if (this._decorations.ContainsKey(i))
        soldier = soldier + ", Decoration: " + this._decorations.ElementAt(i).ToString();
      soldierList.Add(soldier);
    }
    return string.Join("; ", soldierList);
  }

  public class Decoration
  {
    public bool Bronze;
    public bool Silver;
    public bool Gold;

    public override string ToString()
    {
      return (this.Bronze ? "Bronze," : "") + (this.Silver ? "Silver," : "") + (this.Gold ? "Gold" : "")
    }
  }
}

用法:

Soldiers soldiers = new Soldiers(new string[] { "SoldierA" , "SoldierB" , "SoldierC" });

soldiers[0].Gold = true;
soldiers[0].Silver = true;
soldiers[2].Bronze = true;
Console.Write(soldiers.ToString()) // "SoldierA, Decoration: Silver,Gold; SoldierB; SoldierC, Decoration: Bronze";