Шаблон Приспособленец применяется для уменьшения затрат при работе с большим количеством объектов. Приспособленец – это разделяемый объект, который можно использовать одновременно в нескольких контекстах. Чтобы это стало возможным, у объекта выделяют внутреннее и внешнее состояния. Внутреннее состояние (intrinsic state) хранится в приспособленце и состоит из информации, не зависящей от контекста. Именно поэтому оно может разделяться. Внешнее состояние (extrinsic state) зависит от контекста и изменяется вместе с ним, поэтому не подлежит разделению. Клиент отвечает за передачу внешнего состояния приспособленцу, когда в этом возникает необходимость.
Опишем компоненты шаблона Приспособленец (рис. 6). Класс Flyweight является базовым классом для любого приспособленца и отражает возможность передачи в приспособленец внешнего состояния. От этого класса наследуются конкретные классы приспособленцев – как с внутренним состоянием (ConcreteFlyweight), так и без него (UnsharedFlyweight). Класс FlyweightFactory – это фабрика приспособленцев, которая содержит метод для получения необходимого приспособленца по ключу.
|
|
Рис. 6. Диаграмма шаблона Приспособленец.
Приведём пример использования шаблона Приспособленец. Пусть необходимо работать с текстом, состоящим из букв латинского алфавита и пробельных символов. Абстрактный класс Character описывает один символ текста, занимающий определённую позицию (она играет роль внешнего состояния).
public abstract class Character
{
public abstract void Display(int position);
}
У класса Character есть два наследника: класс Latin хранит символ латинского алфавита (это его разделяемое внутреннее состояние), класс Whitespace представляет пробел (и не имеет разделяемого состояния).
public class Latin: Character
{
public char Symbol { get; set; }
public override void Display(int position)
{
Console.WriteLine("{0} (position {1})", Symbol, position);
}
}
public class Whitespace: Character
{
public override void Display(int position)
{
Console.WriteLine("_ (position {0})", position);
}
}
Для эффективного хранения символов используем класс CharacterFactory.
public class CharacterFactory
{
private Dictionary<char, Character> _chars =
new Dictionary<char, Character>();
public Character GetCharacter(char key)
{
if (!_chars.ContainsKey(key))
{
if (key == ' ')
{
_chars.Add(key, new Whitespace());
}
else
{
_chars.Add(key, new Latin {Symbol = key});
}
}
return _chars[key];
}
}
Клиентский код использует фабрику, чтобы получить необходимый объект-приспособленец. После этого у приспособленца устанавливается внешнее состояние, а затем этот объект используется.
var document = "AA BB AB";
var chars = document.ToCharArray();
var f = new CharacterFactory();
// position - это внешнее состояние
var position = 0;
// используем для каждого символа объект-приспособленец
foreach (var c in chars)
{
var character = f.GetCharacter(c);
character.Display(position++);
}