Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Шаблоны и архитектура программ.doc
Скачиваний:
12
Добавлен:
04.05.2019
Размер:
558.08 Кб
Скачать

3.12. Некоторые неклассические шаблоны проектирования

Набор шаблонов проектирования не ограничивается 23 шаблонами из книги «Design Patterns». Со временем список шаблонов расширялся. Некоторые популярные шаблоны представлены в данном параграфе.

Неизменный объект (Immutable object)

Шаблон Неизменяемый объект налагает запрет на изменение содержимого объекта после того, как объект был создан. Это повышает надежность кода при использовании объекта и уменьшает затраты на параллельный доступ к нему.

При практической реализации шаблона обычно придерживаются следующих правил:

  • начальной установкой полей объекта занимается конструктор и только он – не существует методов, которые бы изменяли внутренне состояние объекта;

  • состояние объекта доступно посредством открытых свойств «только для чтения»;

  • если метод получает информацию о новом состоянии объекта, то в теле метода для сохранения состояния создается новый экземпляр объекта.

В качестве иллюстрирующего кода для шаблона Неизменяемый объект приведем реализацию класса, описывающего координаты предмета.

public class Position

{

private int x;

private int y;

public int X { get { return x; } }

public int Y { get { return y; } }

public Position(int x, int y)

{

this.x = x;

this.y = y;

}

public Position Offset(int deltaX, int deltaY)

{

return new Position(x + deltaX, y + deltaY);

}

}

Заметим, что с точки зрения .NET Framework, неизменяемые объекты можно рассматривать как попытку смоделировать поведение типов значений при помощи ссылочных типов. Классическим примером неизменяемого объекта в .NET Framework является тип string. При практической реализации неизменяемого объекта могут дополнительно переопределяться операции проверки на равенство и получения копии.

Пул объектов (Object pool)

Пул объектов – это порождающий шаблон проектирования, который представляет собой набор инициализированных и готовых к использованию объектов. Когда системе требуется объект, он не создаётся, а берётся из пула. Когда объект больше не нужен, он не уничтожается, а возвращается в пул.

Пул объектов обычно применяется для повышения производительности, когда создание объекта в начале работы и уничтожение его в конце приводит к большим затратам. Особенно заметно повышение производительности, когда объекты часто создаются-уничтожаются, но одновременно существует лишь небольшое их число.

При практической реализации шаблона особого внимания заслуживает стратегия поведения в случае переполнения пула. В этом случае возможна одна из трёх стратегий: расширение пула, отказ в создании объекта и аварийный останов, ожидание освобождения одного из объектов в пуле.

Отложенная инициализация (Lazy initialization)

Отложенная (ленивая) инициализация – это приём в программировании, когда некоторая ресурсоёмкая операция (создание объекта, вычисление значения) выполняется непосредственно перед тем, как будет использован её результат. Таким образом, инициализация выполняется «по требованию», а не заблаговременно. Частный случай ленивой инициализации – создание объекта в момент обращения к нему – является одним из порождающих шаблонов проектирования. Как правило, он используется в сочетании с такими шаблонами как Фабричный метод, Одиночка и Заместитель.

Рассмотрим один из вариантов работы с отложенной инициализацией. Создадим обобщенный класс Lazy<T>, который будет представлять загрузку по требованию, а так же кэшировать результат вычислений для дальнейших обращений к ним.

public class Lazy<T>

{

private readonly Func<T> func;

private T result;

private bool hasValue;

public Lazy(Func<T> func)

{

this.func = func;

hasValue = false;

}

public T Value

{

get

{

if (!hasValue)

{

result = func();

hasValue = true;

}

return result;

}

}

}

Класс Lazy<T> имеет три поля:

  1. func – делегат, инкапсулирующего передаваемый метод;

  2. result – поле для хранения результата вычислений;

  3. hasValue – флаг для обозначения, производились ли уже вычисления.

Описанный класс допускает следующий вариант использования:

Lazy<int> lazy = new Lazy<int>(() =>

{

Console.WriteLine("calculating...");

return 42;

});

Console.WriteLine("starting...");

Console.WriteLine("result = {0}", lazy.Value);

Console.WriteLine("result (again) = {0}", lazy.Value);