Understanding the Flyweight pattern
Asked Answered
W

4

18

Intent:

The intent of this pattern is to use sharing to support a large number of objects that have part of their internal state in common where the other part of state can vary.

Objects can share state via static fields.

What is the difference between sharing internal state of a large number of objects using the flyweight pattern and using static fields?

Is the pool of objects that the flyweight provides via its Factory what the flyweight is really all about?

Walachia answered 15/5, 2014 at 16:36 Comment(0)
L
18

Using static fields, there can only ever be one instance of the object in use at any one point in time. Using the flyweight pattern, you can have any number of different instances in use simultaneously, (each one of which is used multiple times). The canonical example of the flyweight pattern is for a text editor, where you need an object instantiated for each and every character in the document. Instead of having one object in memory for each character in a 10,000 word document, you then only need 26 objects, (assuming document only uses lower case letters), one for the letter 'a', one for the letter 'b', etc., and they are reused, transiently, over and over again throughout the document, each time you need to perform some function or action requiring an 'a' object.

EDIT: to answer question from first comment below:
So, since you need 26 different objects, making a Letter class that was a static, or a singleton, wouldn't work. If it was a static, you can't make any instances, and so whatever the static values would have to be appropriate for every place in the code where you made use of it. If it was a singleton, then of course you only have one object. Every property would have to be adjustable (and adjusted) every time you used it. To use this pattern for the letters in the alphabet, you have to have 26 different classes, one for each letter...

Also, the "part of the class that can vary" really means that some fields represent state that is different for every instance of the class. Whereas the part that is in common means that the values of those common fields are in common for all uses of the object matching those state values (all the 'a's for example), not for every instance of the class.

Again, using the text editor as an example. Every place in your code that you need to deal with a character that is an 'a', you would first, go to the data structure that stores your 26 instances of character objects, and fetch the 'a' instance, You would first modify/change the varying properties (the properties not tied to it's nature as an 'a', but perhaps to it's font size, position, color, etc.) to match the needs for this specific character 'a' in the document.
Then you would utilize the object to do whatever it is you need to do with it, and then return it to the storage structure for reuse the next time your code needs an 'a'.

Lancaster answered 15/5, 2014 at 16:43 Comment(4)
If the letter class was a static, or a singleton, that wouldn't work. Why? From your explanation it is not obvious.Autosome
So if I'm understanding the text editor example correctly: if I have 10000 letters in my document, instead of having 10000 Letter objects, I simply have 10000 references to any of these 26 Letter objects?Halcomb
No, you don't hold a reference to the objects, you only use the 26 objects on demand when you need one. For example, if yoyu need to paint a screen with 1200 characters on it, you see what the first character is, say it's an 'a', so you get the 'a' object, set it's properties consistent with the document character it is going to transiently represent, use the object, (maybe to paint the 'a' on the screen), then forget the object (it is still in the 26 character object store), and iterate to the next character.Lancaster
This is a good example. A more complicated example of structured text is in a compiler; when decomposing the text of a program one might want to have a flyweight instance for int, ;, null, and so on, because you know that you're going to be seeing a lot of those.Loon
G
8

The Flyweight pattern is used to avoid the overhead of large numbers of very similar classes. There are cases in programming where it seems that you need to generate a very large number of small class instances to represent data. Sometimes you can greatly reduce the number of different classes that you need to instantiate if you can recognize that the instances are fundamentally the same except for a few parameters. If you can move those variables outside the class instance and pass them in as part of a method call, the number of separate instances can be greatly reduced by sharing them.

In this context, it's important to bear in mind that the Flyweight was invented in an era where C# was nothing more than a rough sketch on some power point charts. And the maturation of the language was informed by some of these patterns implicitly. C# includes class members...

It is more typical to declare a non-static class with some static members, than to declare an entire class as static. Two common uses of static fields are to keep a count of the number of objects that have been instantiated, or to store a value that must be shared among all instances.

Source C# statics on MSDN

Taking things further, WPF technology popularized shared resources, and the result is often declarative code only.

So if your language of choice is C#, you may be advised to consider the Flyweight pattern against inherent properties that already exist in the language.

Gabriello answered 15/5, 2014 at 17:2 Comment(4)
among all instances - not all instances may need that value.Bureaucratic
As far as I have found out so far, WPF's DataTemplateSelector does require procedural coding (to override the SelectTemplate method). MS have not added any way to select templates declaratively, hence (like many parts of WPF) the selector is only declarative in use (effectively, one line in XAML), while the bulk of the code is still non-declarative.Altaf
@O.R.Mapper that is true, there is no declarative selector. Write your own. It is doesnt take long.Bureaucratic
@Gusdor: "not long" is a matter of perspective. Writing the logical equivalent of someBool ? "TrueTemplate" : "FalseTemplate" (which could be 4 lines of XAML, or less) as a DataTemplateSelector subclass in C# takes comparably long (and includes tasks such as detecting and loading resources in code - just look at the comparably simple example in the DataTemplateSelector docs.Altaf
C
3

While patterns and their implementations are a bit subjective, using statics is a valid - albeit simplest possible - way to achieve Flyweight.

If you can use statics, that's great. Otherwise you can do something like you've touched on ... your factory that constructs flyweight objects can assign/reference the proper shared object.

Conventional answered 15/5, 2014 at 17:0 Comment(0)
T
1

Here is some example, it print all of the soldiers and their medals.

Because not all of the soldiers are decorated we are using the flyweight design pattern.

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

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

  public Medal this[int index]
  {
    get
    {
      Medal medal = new Medal();
      this._medals.Add(index, medal);
      return this._medals[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._medals.ContainsKey(i))
        soldier = soldier + ", Medal: " + this._medals.ElementAt(i).ToString();
      soldierList.Add(soldier);
    }
    return string.Join("; ", soldierList);
  }

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

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

Usage:

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, Medal: Silver,Gold; SoldierB; SoldierC, Medal: Bronze";
Terret answered 14/11, 2017 at 11:20 Comment(1)
I don't think this is a very good example of the Fly-Weight pattern. It doesn't actually reuse any instances. In fact, if I am reading the code correctly, it actually creates duplicate Medal instances if the same Medal is awarded more than once, which is exactly what Fly-Weight was designed to avoid.Sirmons

© 2022 - 2024 — McMap. All rights reserved.