Հարմարեցնող (նախագծման ձևանմուշ)

Հարմարեցնող
ՏեսակԿառուցվածքային
ՆշանակությունՀիշողության հետ աշխատանքը թեթևացնելու համար
Նկարագրությունը ԳօՖի
"Design Patterns" գրքում
Այո

Հարմարեցնող (անգլ.՝ Flyweight), կառուցվածքային նախագծման ձևանմուշ, որի դեպքում իրեն որպես ունիկալ ներկայացնող օբյեկտը փաստացի այդպիսին չի հանդիսանում։

Ընդհանուր հասկացողություններ

[խմբագրել | խմբագրել կոդը]
  • Client - հայցող
  • Instance - նմուշ
  • Implementation - իրականացում
  • Product - արգասիք

Օպտիմիզացնում է հիշողության հետ աշխատանքը՝ թույլ չտալով ստեղծել էլեմենտների նմուշներ, որոնք ունեն ընդհանուր հատկություններ։

Նկարագրություն

[խմբագրել | խմբագրել կոդը]

Հարմարեցնող ձևանմուշն օգտագործվում է բազմաթիվ փոքր օբյեկտների հետ կապված ռեսուրսների նվազման համար։ Այս ձևանմուշը նախագծելու ժամանակ պետք է առանձնացնել նրա ներքին և արտաքին հատկանիշները։ Ներքին հատկությունները միշտ մնում են անփոփոխ, իսկ արտաքին հատկությունները կարող են կախված լինել կոնտեքստի օգտագործումից և նրանում պետք է իրագործել անհրածեշտ փոփոխություններ։

Հարմարեցնողը լրացնում է Ֆաբրիկային մեթոդ ձևանմուշն այնպես, որ Ֆաբրիկային մեթոդին հայցվորի նոր օբյեկտ ստեղծելու հայցի դեպքում համակարգը սկսում է ման գալ նմանատիպ պարամետրերով օբյեկտ և այն վերադարձնում է հայցողին։ Եթե այդպիսի օբյեկտ համակարգը չի գտնում, ապա ստեղծվում է։

#include <map>
#include <iostream>

// "Flyweight"
class Character
{
public:
    virtual ~Character() {}
    virtual void display() const = 0;

protected:
    char mSymbol;
    int  mWidth;
    int  mHeight;
    int  mAscent;
    int  mDescent;
    int  mPointSize;
};

// "ConcreteFlyweight"
class ConcreteCharacter : public Character
{
public:
    // Constructor
    ConcreteCharacter( char aSymbol, int aPointSize )
    {
        mSymbol = aSymbol;
        mWidth = 120;
        mHeight = 100;
        mAscent = 70;
        mDescent = 0;
        mPointSize = aPointSize;
    }

    // from Character
    virtual void display() const {
        std::cout << mSymbol << " ( PointSize " << mPointSize << " )\n";
    }
};

// "FlyweightFactory"
template < int POINT_SIZE = 10 >
class CharacterFactory
{
public:
    const Character& getCharacter( char aKey )
    {
        // Uses "lazy initialization"
        Characters::const_iterator it = mCharacters.find( aKey );
        if ( mCharacters.end() == it ) {
            const Character* character = new ConcreteCharacter(aKey, POINT_SIZE);
            mCharacters[aKey] = character;
            return *character;
        } else {
            return *it->second;
        }
    }

    virtual ~CharacterFactory(){
        for (Characters::const_iterator it = mCharacters.begin(); it != mCharacters.end(); ++it)
             delete it->second;
        }

private:
    typedef std::map < char, const Character* > Characters;
    Characters mCharacters;
};

int main(){
    std::string document = "AAZZBBZB";

    CharacterFactory<12> characterFactory;

    for (std::string::const_iterator it = document.begin(); it != document.end(); ++it){
        const Character& character = characterFactory.getCharacter( *it );
        character.display();
    }
    return 0;
}
using System;
using System.Collections;

namespace Flyweight
{

  class MainApp
  {
    static void Main()
    {
      // Build a document with text
      string document = "AAZZBBZB";
      char[] chars = document.ToCharArray();

      CharacterFactory f = new CharacterFactory();

      // extrinsic state
      int pointSize = 10;

      // For each character use a flyweight object
      foreach (char c in chars)
      {
        pointSize++;
        Character character = f.GetCharacter(c);
        character.Display(pointSize);
      }

      // Wait for user
      Console.Read();
    }
  }

  // "FlyweightFactory"

  class CharacterFactory
  {
    private Hashtable characters = new Hashtable();

    public Character GetCharacter(char key)
    {
      // Uses "lazy initialization"
      Character character = characters[key] as Character;
      if (character == null)
      {
        switch (key)
        {
          case 'A': character = new CharacterA(); break;
          case 'B': character = new CharacterB(); break;
            //...
          case 'Z': character = new CharacterZ(); break;
        }
        characters.Add(key, character);
      }
      return character;
    }
  }

  // "Flyweight"

  abstract class Character
  {
    protected char symbol;
    protected int width;
    protected int height;
    protected int ascent;
    protected int descent;
    protected int pointSize;

    public abstract void Display(int pointSize);
  }

  // "ConcreteFlyweight"

  class CharacterA : Character
  {
    // Constructor
    public CharacterA()
    {
      this.symbol = 'A';
      this.height = 100;
      this.width = 120;
      this.ascent = 70;
      this.descent = 0;
    }

    public override void Display(int pointSize)
    {
      this.pointSize = pointSize;
      Console.WriteLine(this.symbol +
        " (pointsize " + this.pointSize + ")");
    }
  }

  // "ConcreteFlyweight"

  class CharacterB : Character
  {
    // Constructor
    public CharacterB()
    {
      this.symbol = 'B';
      this.height = 100;
      this.width = 140;
      this.ascent = 72;
      this.descent = 0;
    }

    public override void Display(int pointSize)
    {
      this.pointSize = pointSize;
      Console.WriteLine(this.symbol +
        " (pointsize " + this.pointSize + ")");
    }

  }

  // ... C, D, E, etc.

  // "ConcreteFlyweight"

  class CharacterZ : Character
  {
    // Constructor
    public CharacterZ()
    {
      this.symbol = 'Z';
      this.height = 100;
      this.width = 100;
      this.ascent = 68;
      this.descent = 0;
    }

    public override void Display(int pointSize)
    {
      this.pointSize = pointSize;
      Console.WriteLine(this.symbol +
        " (pointsize " + this.pointSize + ")");
    }
  }
}
import java.util.*;

public enum FontEffect {
    BOLD, ITALIC, SUPERSCRIPT, SUBSCRIPT, STRIKETHROUGH
}

public final class FontData {
    /**
     * A weak hash map will drop unused references to FontData.
     * Values have to be wrapped in WeakReferences, 
     * because value objects in weak hash map are held by strong references.
     */
    private static final WeakHashMap<FontData, WeakReference<FontData>> flyweightData =
        new WeakHashMap<FontData, WeakReference<FontData>>();
    private final int pointSize;
    private final String fontFace;
    private final Color color;
    private final Set<FontEffect> effects;

    private FontData(int pointSize, String fontFace, Color color, EnumSet<FontEffect> effects) {
        this.pointSize = pointSize;
        this.fontFace = fontFace;
        this.color = color;
        this.effects = Collections.unmodifiableSet(effects);
    }

    public static FontData create(int pointSize, String fontFace, Color color,
        FontEffect... effects) {
        EnumSet<FontEffect> effectsSet = EnumSet.noneOf(FontEffect.class);
        effectsSet.addAll(Arrays.asList(effects));
        // We are unconcerned with object creation cost, we are reducing overall memory consumption
        FontData data = new FontData(pointSize, fontFace, color, effectsSet);
        if (!flyweightData.containsKey(data)) {
            flyweightData.put(data, new WeakReference<FontData> (data));
        }
        // return the single immutable copy with the given values
        return flyweightData.get(data).get();
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof FontData) {
            if (obj == this) {
                return true;
            }
            FontData other = (FontData) obj;
            return other.pointSize == pointSize && other.fontFace.equals(fontFace)
                && other.color.equals(color) && other.effects.equals(effects);
        }
        return false;
    }

    @Override
    public int hashCode() {
        return (pointSize * 37 + effects.hashCode() * 13) * fontFace.hashCode();
    }

    // Getters for the font data, but no setters. FontData is immutable.
}