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

Одиночка (Singleton)

Шаблон Одиночка гарантирует создание единственного экземпляра объекта некоторого класса.

Необходимость в единичных объектах часто возникает при программировании физических устройств. Если в системе установлен единственный принтер, то нужно быть уверенным, что в программе имеется единственный объект, описывающий этот принтер и предоставляющий доступ к его настройкам. Иначе возможна ситуация рассогласования – различные (возможно, противоречивые) настройки будут выполняться в разных частях программы над одним физическим объектом.

Шаблон Одиночка добавляет функциональность путём модификации существующего класса. Модификация требует следующих шагов.

  • Конструктор класса делается закрытым (private).

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

  • Для доступа к закрытому статическому полю добавляется открытое статическое свойство.

Рис. 12 иллюстрирует указанные шаги.

Рис. 12. UML-диаграмма шаблона Одиночка.

Код, который соответствует описанным шагам реализации шаблона, представлен ниже.

public sealed class Singleton

{

// Закрытый конструктор

private Singleton() { }

// Закрытое поле, хранит экземпляр класса

private static readonly Singleton uniqueInstance =

new Singleton();

// Открытое свойство для доступа к экземпляру

public static Singleton Instance

{

get { return uniqueInstance; }

}

}

Возможен вариант, когда инициализация внутреннего экземпляра проводится при первом обращении к открытому свойству:

// Один из вариантов реализации шаблона Singleton

public sealed class Singleton

{

private Singleton() { }

private static Singleton uniqueInstance;

public static Singleton Instance

{

get

{

if (uniqueInstance == null)

{

uniqueInstance = new Singleton();

}

return uniqueInstance;

}

}

}

Однако такой подход не является потокобезопасным4, и использовать его не рекомендуется.

3.7. Порождающие шаблоны: абстрактная фабрика и строитель Абстрактная фабрика (Abstract factory)

Шаблон Абстрактная фабрика предназначен для создания объектов, принадлежащих одному набору классов и используемых совместно. Абстрактная фабрика переопределяется в конкретных классах-фабриках, создающих объекты одного набора. Этот шаблон изолирует имена классов и их определения от клиента: единственный способ для клиента получить необходимый объект – это воспользоваться одной из реализаций абстрактной фабрики.

Дизайн шаблона Абстрактная фабрика включает большое число участников, однако он достаточно прост (рис. 13). Клиент хранит ссылку на конкретную фабрику, реализующую интерфейс IFactory. Диаграмма показывает, что один из вариантов установки связи клиента и фабрики – это передача объекта-фабрики в конструкторе клиента. Клиент работает с определённым набором объектов, но использует для этого только реализуемые классами объектов интерфейсы (IProductA и IProductB). Для получения нужного объекта клиент вызывает один из методов фабрики.

Рис. 13. Шаблон абстрактная фабрика.

Рассмотрим пример кода с реализацией шаблона абстрактная фабрика. Отметим одну важную отличительную особенность представленной реализации шаблона. Вместо набора классов-фабрик и классов для объектов клиента используются универсальные шаблоны (generics). Конкретный класс-фабрика получается конструированием из общего универсального шаблона при помощи параметра TBrand.

// Общий интерфейс фабрики

public interface IFactory

{

IBag CreateBag();

IShoes CreateShoes();

}

// Это generic-класс будет конструироваться в конкретные фабрики

public class Factory<TBrand> : IFactory where TBrand : IBrand, new()

{

public IBag CreateBag()

{

return new Bag<TBrand>();

}

public IShoes CreateShoes()

{

return new Shoes<TBrand>();

}

}

// Два интрефейса, с которыми работает клиент

public interface IBag

{

string Material { get; }

}

public interface IShoes

{

int Price { get; }

}

// Generic-классы для конкретных классов-продуктов

public class Bag<TBrand> : IBag where TBrand : IBrand, new()

{

private readonly TBrand myBrand;

public Bag()

{

myBrand = new TBrand();

}

public string Material

{

get { return myBrand.Material; }

}

}

public class Shoes<TBrand> : IShoes where TBrand : IBrand, new()

{

private readonly TBrand myBrand;

public Shoes()

{

myBrand = new TBrand();

}

public int Price

{

get { return myBrand.Price; }

}

}

// Интерфейс для описания брэндов и конкретные брэнды

public interface IBrand

{

int Price { get; }

string Material { get; }

}

public class Gucci : IBrand

{

public int Price

{

get { return 1000; }

}

public string Material

{

get { return "Crocodile skin"; }

}

}

public class Poochy : IBrand

{

public int Price

{

get { return new Gucci().Price / 3; }

}

public string Material

{

get { return "Plastic"; }

}

}

public class Client<TBrand> where TBrand : IBrand, new()

{

public void ClientMain()

{

IFactory factory = new Factory<TBrand>();

var bag = factory.CreateBag();

var shoes = factory.CreateShoes();

Console.WriteLine("A Bag is made from " + bag.Material);

Console.WriteLine("Shoes’ cost is" + shoes.Price);

}

}

public static class AbstractFactoryExample

{

private static void Main()

{

new Client<Poochy>().ClientMain();

new Client<Gucci>().ClientMain();

}

}