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

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

Ընդհանուր հասկացողություններ
 Client - հայցող
 Instance - նմուշ
 Implementation - իրականացում
 Product - արգասիք

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

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

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

Օրինակներ

C++ 
#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;
}

C# 
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 + ")");
    }
  }
}

Java 
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.
}

Ծանոթագրություններ 

Ծրագրավորում