Приспособленец (Flyweight) — различия между версиями
Admin (обсуждение | вклад) (→Достоинства и недостатки) |
Admin (обсуждение | вклад) (→Варианты) |
||
Строка 125: | Строка 125: | ||
* Уменьшение количества обрабатываемых объектов | * Уменьшение количества обрабатываемых объектов | ||
* При вычислении всякий раз контекстной информации теряется производительность | * При вычислении всякий раз контекстной информации теряется производительность | ||
− | |||
− | |||
− |
Версия 11:29, 8 августа 2014
Назначение
Уменьшает количество объектов системы с многочисленными низкоуровневыми особенностями путем совместного использования подобных объектов.
Описание
В некоторых приложениях имеется множество небольших объектов, и задача экономии памяти выходит на первый план. Паттерн Flyweight предназначен для уменьшения количества объектов в системе за счет их совместного использования. Группа объектов может быть объединена в один объект если какая-то часть состояния у них совпадает. Несовпадающую же часть (так называемый внешний контекст) предлагается передавать в качестве параметра операции.
Назначение
Паттерн Flyweight можно использовать в случаях когда:
- в приложении имеется множество почти одинаковых объектов
- различающиеся части почти одинаковых объектов можно отделить от одинаковых и заменить эти почти одинаковые объекты одним совместно используемым объектом, передавая различающуюся часть как параметр операции
Реализация
Диаграмма классов
Участники
Пример
В графическом редакторе не надо хранить каждый символ в виде объекта. Достаточно хранить по одному объекту для каждого из используемых символов кодовой таблицы и в метод рисования передавать контекст рисования.
В данном примере в контексте хранится текущая позиция рисования, которая после каждого рисования символа увеличивается на 1. Кроме того, в контексте хранится набор интервалов. Если символ попадает в один из интервалов, то он рисуется жирным.
Таким образом, у каждого объекта есть внутреннее состояние (символ, который он представляет) и внешнее (позиция в тексте плюс набор интервалов), которое не хранится вместе с объектом, а передается ему как параметр в качестве внешнего контекста.
Приспособленцем здесь выступает символ, который приспосабливается к ситуации в зависимости от контекста.
Без паттерна Приспособленец атрибут жирности символа требовалось бы хранить в классе символа, что при большом количестве символов расточительно. Паттерн Приспособленец позволяет хранить информацию о жирности в виде набора интервалов, что существенно компактнее. Кроме этого, паттерн приспособленец вместо множества объектов, представляющих один символ, хранит лишь один объект.
Код примера
class MainApp
{
static void Main()
{
string Str = "AAZZBBZB";
CharacterFactory factory = new CharacterFactory();
Context context = new Context();
context.AddInterval(2, 4);
context.AddInterval(6, 7);
foreach (char c in Str)
{
Character character = factory.GetCharacter(c); // получить приспособленца
character.Draw(context);
}
}
}
class Pair
{
public int Left,Right;
public Pair(int left, int right)
{
Left = left;
Right = right;
}
}
class Context
{
private int pos = 1;
private List<Pair> list = new List<Pair>();
public void AddInterval(int left, int right)
{
list.Add(new Pair(left,right));
}
public void Next()
{
pos++;
}
public bool InInterval()
{
foreach (var p in list)
{
if (pos >= p.Left && pos <= p.Right)
return true;
}
return false;
}
}
class CharacterFactory
{
private Dictionary<char, Character> characters = new Dictionary<char, Character>();
public Character GetCharacter(char key)
{
Character character = null;
if (characters.ContainsKey(key)) // если есть такой приспособленец
{
character = characters[key]; // то просто вернуть его
}
else
{
character = new Character(key);
characters.Add(key, character); // иначе создать, добавить к словарю приспособленцев и вернуть
}
return character;
}
}
class Character
{
private char symbol;
public Character(char sym)
{
symbol = sym;
}
public void Draw(Context context)
{
if (context.InInterval())
Console.WriteLine("Symbol = {0} BOLD", symbol); // попавшие в один из интервалов контекста символы рисуются жирным
else Console.WriteLine("Symbol = {0}", symbol);
context.Next(); // меняем контекст - позицию символа
}
}
Достоинства и недостатки
- Уменьшение количества обрабатываемых объектов
- При вычислении всякий раз контекстной информации теряется производительность