Հարմարեցնող | |
---|---|
Տեսակ | Կառուցվածքային |
Նշանակություն | Հիշողության հետ աշխատանքը թեթևացնելու համար |
Նկարագրությունը ԳօՖի "Design Patterns" գրքում | Այո |
Հարմարեցնող (անգլ.՝ Flyweight), կառուցվածքային նախագծման ձևանմուշ, որի դեպքում իրեն որպես ունիկալ ներկայացնող օբյեկտը փաստացի այդպիսին չի հանդիսանում։
Օպտիմիզացնում է հիշողության հետ աշխատանքը՝ թույլ չտալով ստեղծել էլեմենտների նմուշներ, որոնք ունեն ընդհանուր հատկություններ։
Հարմարեցնող ձևանմուշն օգտագործվում է բազմաթիվ փոքր օբյեկտների հետ կապված ռեսուրսների նվազման համար։ Այս ձևանմուշը նախագծելու ժամանակ պետք է առանձնացնել նրա ներքին և արտաքին հատկանիշները։ Ներքին հատկությունները միշտ մնում են անփոփոխ, իսկ արտաքին հատկությունները կարող են կախված լինել կոնտեքստի օգտագործումից և նրանում պետք է իրագործել անհրածեշտ փոփոխություններ։
Հարմարեցնողը լրացնում է Ֆաբրիկային մեթոդ ձևանմուշն այնպես, որ Ֆաբրիկային մեթոդին հայցվորի նոր օբյեկտ ստեղծելու հայցի դեպքում համակարգը սկսում է ման գալ նմանատիպ պարամետրերով օբյեկտ և այն վերադարձնում է հայցողին։ Եթե այդպիսի օբյեկտ համակարգը չի գտնում, ապա ստեղծվում է։
#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.
}
|