- •Лабораторная работа №4 Шаблоны проектирования
- •Теоретические сведения
- •Отношения между классами. На диаграммах классов языка uml
- •Суть паттерна
- •Решение
- •Адаптер объектов
- •Адаптер классов
- •Адаптер классов не нуждается во вложенном объекте, так как он может одновременно наследовать и часть существующего класса, и часть сервиса.
- •Фасад (Facade)
- •Концептуальный пример
- •Program.Cs:
- •Output.Txt: Результат выполнения
- •Изолирует клиентов от компонентов подсистемы Уменьшая тем самым число объектов, с которыми клиентам приходится иметь дело, упрощая работу с подсистемой.
- •Позволяет ослабить связанность между подсистемой и ее клиентами.
- •Фасад не исключает возможности приложениям напрямую обращаться к классам подсистемы, если это необходимо.
- •Заместитель (Proxy)
- •3. Локальный запуск сервиса (удалённый прокси). Когда настоящий сервисный объект находится на удалённом сервере.
- •Концептуальный пример
- •Декоратор (Decorator)
- •// Объект
- •} //Ptr2 выходит из области видимости, но объект не //освобождается, потому что есть ptr, который по-прежнему //ссылается на него } //ptr выходит из области видимости, и объект уничтожается
- •Пример на языке c#
- •Порождающие шаблоны Абстрактная фабрика (Abstract Factory)
- •1. Шаблон реализуется созданием абстрактного класса Factory, который представляет собой интерфейс для создания компонентов системы.
- •3. Таким образом, еще раз - предоставляет интерфейс для создания семейств, связанных между собой, или зависимых объектов.
- •Клиент пользуется только интерфейсами, заданными в классах «Абстрактная фабрика» и «Абстрактный продукт».
- •Фабричный метод (Factory Method)
- •Void info() {
- •Void info() {
- •Void info() {
- •Int main()
- •Одиночка (Singleton) Суть паттерна
- •If(!p_instance)
- •Поведенческие шаблоны Стратегия (Strategy)
- •Стратегии построения пути.
- •Структура
- •Концептуальный пример
- •Program.Cs: Пример структуры паттерна
- •Output.Txt: Результат выполнения
- •Void useStrategy(void)
- •Void setStrategy(Strategy* o)
- •Int main(int /*argc*/, char* /*argv*/[])
- •Наблюдатель (Observer) Суть паттерна
- •Решение
- •Структура
- •Шаги реализации
- •Концептуальный пример
- •Program.Cs: Пример структуры паттерна
- •// Random.Next(…) - Метод, возвращает случайное целое число //в указанном диапазоне.
- •Output.Txt: Результат выполнения
- •Использование паттерна Observer
- •Команда (Command)
- •Структура
- •Output.Txt: Результат выполнения
- •Задания для лабораторной работы
1. Шаблон реализуется созданием абстрактного класса Factory, который представляет собой интерфейс для создания компонентов системы.
Затем пишутся классы, реализующие этот интерфейс.
2. Абстрактная фабрика — шаблон проектирования, позволяющий изменять поведение системы, варьируя создаваемыми объектами, при этом сохраняя интерфейсы.
Еще раз:
- Он позволяет создавать целые группы взаимосвязанных объектов, которые, будучи созданными одной фабрикой, реализуют общее поведение.
- Шаблон реализуется созданием абстрактного класса Factory, который представляет собой интерфейс для создания компонентов системы – конкретных фабрик объектов, реализующих группы взаимосвязанных объектов.
- Этот шаблон предоставляет интерфейс для создания семейств взаимосвязанных или взаимозависимых объектов, не специфицируя их конкретных классов.
3. Таким образом, еще раз - предоставляет интерфейс для создания семейств, связанных между собой, или зависимых объектов.
От класса «Абстрактная фабрика» наследуются классы Конкретных Фабрик, которые содержат методы создания Конкретных объектов-продуктов, являющихся наследниками класса «Абстрактный продукт», объявляющего интерфейс для их создания.
Клиент пользуется только интерфейсами, заданными в классах «Абстрактная фабрика» и «Абстрактный продукт».
Применяется в случаях:
Когда программа должна быть независимой от процесса и типов создаваемых новых объектов.
Когда необходимо создать семейства или группы взаимосвязанных объектов, исключая возможность одновременного использования объектов из разных этих наборов в одном контексте.
Плюсы:
изолирует конкретные классы;
упрощает замену семейств продуктов;
гарантирует сочетаемость продуктов.
Минусы:
сложно добавить поддержку нового вида продуктов.
Концептуальный пример
Этот пример показывает структуру паттерна Абстрактная фабрика, а именно — из каких классов он состоит, какие роли эти классы выполняют и как они взаимодействуют друг с другом.
Program.cs: Пример структуры паттерна
using System;
namespace DesignPatterns.AbstractFactory.Conceptual
{
// Интерфейс Абстрактной Фабрики объявляет набор методов, //которые возвращают различные абстрактные продукты.
//Эти продукты называются семейством и связаны темой или //концепцией высокого уровня.
// Продукты одного семейства обычно могут
// взаимодействовать между собой. Семейство продуктов //может иметь несколько вариаций, но продукты одной //вариации несовместимы с продуктами другой.
public interface IAbstractFactory
{
IAbstractProductA CreateProductA ();
IAbstractProductB CreateProductB ();
}
// Конкретная Фабрика производит семейство продуктов
// одной вариации. Фабрика гарантирует совместимость
// полученных продуктов. Обратите внимание, что //сигнатуры методов Конкретной Фабрики возвращают
// абстрактный продукт, в то время как внутри //метода создается экземпляр конкретного продукта.
class ConcreteFactory1 : IAbstractFactory
{
public IAbstractProductA CreateProductA()
{
return new ConcreteProductA1();
}
public IAbstractProductB CreateProductB()
{
return new ConcreteProductB1();
}
}
// Каждая Конкретная Фабрика имеет соответствующую
// вариацию продукта.
class ConcreteFactory2 : IAbstractFactory
{
public IAbstractProductA CreateProductA()
{
return new ConcreteProductA2();
}
public IAbstractProductB CreateProductB()
{
return new ConcreteProductB2();
}
}
// Каждый отдельный продукт семейства продуктов должен //иметь базовый интерфейс. Все вариации продукта должны //реализовывать этот интерфейс.
public interface IAbstractProductA
{
string UsefulFunctionA();
}
// Конкретные продукты создаются соответствующими //Конкретными Фабриками.
class ConcreteProductA1 : IAbstractProductA
{
public string UsefulFunctionA()
{
return "The result of the product A1.";
}
}
class ConcreteProductA2 : IAbstractProductA
{
public string UsefulFunctionA()
{
return "The result of the product A2.";
}
}
// Базовый интерфейс другого продукта. Все продукты
//могут взаимодействовать друг с другом,
// но правильное взаимодействие возможно только между
// продуктами одной и той же конкретной вариации.
public interface IAbstractProductB
{
// Продукт B способен работать самостоятельно...
string UsefulFunctionB();
//а также взаимодействовать с Продуктами B той же вариации.
// Абстрактная Фабрика гарантирует, что все продукты,
// которые она создает, имеют одинаковую вариацию
//и, следовательно, совместимы.
string AnotherUsefulFunctionB (IAbstractProductA collaborator);
}
// Конкретные Продукты создаются соответствующими //конкретными Фабриками.
class ConcreteProductB1 : IAbstractProductB
{
public string UsefulFunctionB()
{
return "The result of the product B1.";
}
// Продукт B1 может корректно работать только с
//Продуктом A1.
// Тем не менее, он принимает любой экземпляр //Абстрактного Продукта А в качестве аргумента.
public string AnotherUsefulFunctionB(IAbstractProductA collaborator)
{
var result = collaborator.UsefulFunctionA();
return $"The result of the B1 collaborating with the ({result})";
}
}
class ConcreteProductB2 : IAbstractProductB
{
public string UsefulFunctionB()
{
return "The result of the product B2.";
}
// Продукт B2 может корректно работать только с //Продуктом A2.
// Тем не менее, он принимает любой экземпляр //Абстрактного Продукта А в качестве аргумента.
public string AnotherUsefulFunctionB(IAbstractProductA collaborator)
{
var result = collaborator.UsefulFunctionA();
return $"The result of the B2 collaborating with the ({result})";
}
}
// Клиентский код работает с фабриками и продуктами //только через абстрактные типы: Абстрактная Фабрика и //Абстрактный Продукт.
// Это позволяет передавать любой подкласс фабрики или //продукта клиентскому коду, не нарушая его.
class Client
{
public void Main ()
{
// Клиентский код может работать с любым //конкретным классом фабрики.
Console.WriteLine("Client: Testing client code with the first factory type...");
ClientMethod(new ConcreteFactory1());
Console.WriteLine();
Console.WriteLine("Client: Testing the same client code with the second factory type...");
ClientMethod(new ConcreteFactory2());
}
public void ClientMethod(IAbstractFactory factory)
{
var productA = factory.CreateProductA();
var productB = factory.CreateProductB();
Console.WriteLine(productB.UsefulFunctionB());
Console.WriteLine(productB.AnotherUsefulFunctionB(productA));
}
}
class Program
{
static void Main(string[] args)
{
new Client().Main();
}
}
}
Output.txt: Результат выполнения
Client: Testing client code with the first factory type...
The result of the product B1.
The result of the B1 collaborating with the (The result of the product A1.)
Client: Testing the same client code with the second factory type...
The result of the product B2.
The result of the B2 collaborating with the (The result of the product A2.)
Output.txt: Результат выполнения
Клиент: Тестирование клиентского кода с первым заводским типом... Результат продукта B1.
Результат сотрудничества B1 с (результат продукта A1.)
Клиент: Тестирование того же клиентского кода со вторым заводским типом...
Результат продукта B2.
Результат сотрудничества B2 с (результат продукта A2.)
Реализация на C++
//общий интерфейс для данных любого формата
//абстрактный класс «продукта»
class FormattedData {
//...
};
//конкретный формат
class FormattedData1 : public FormattedData {
//...
};
//другой конкретный формат
class FormattedData2 : public FormattedData {
//...
};
//абстрактная фабрика
class AbstractFactory {
public:
virtual FormattedData* createFormattedData() = 0;
//чистая виртуальная функция
};
//конкретная фабрика для создания объектов, содержащих
// данные нужного формата
class FormatFactory : public AbstractFactory {
public:
FormattedData* createFormattedData() {
if(/* some condition */) {
return new FormattedData1();
}
else {
return new FormattedData2();
}
}
};
//использование абстрактной фабрики
int main () {
AbstractFactory* pfactory = new FormatFactory();
FormattedData* pdata = pfactory->createFormattedData();
//send data
//...
if(pfactory) delete pfactory;
if(pdata) delete pdata;
return 0;
}
Еще один пример
…
public class AbstractFactoryExample {
public static void main (String[] args) {
AbstractFactory factory1 = new ConcreteFactory1();
Client client1 = new Client(factory1);
client1.execute();
AbstractFactory factory2 = new ConcreteFactory2();
Client client2 = new Client(factory2);
client2.execute();
}
}
class Client {
private AbstractProductA productA;
private AbstractProductB productB;
Client(AbstractFactory factory) {
productA = factory.createProductA();
productB = factory.createProductB();
}
void execute() {
productB.interact(productA);
}
}
interface AbstractFactory {
AbstractProductA createProductA();
AbstractProductB createProductB();
}
interface AbstractProductA {
void interact(AbstractProductB b);
}
interface AbstractProductB {
void interact (AbstractProductA a);
}
class ConcreteFactory1 implements AbstractFactory {
@Override
public AbstractProductA createProductA() {
return new ProductA1();
}
@Override
public AbstractProductB createProductB() {
return new ProductB1();
}
}
class ConcreteFactory2 implements AbstractFactory {
@Override
public AbstractProductA createProductA() {
return new ProductA2();
}
@Override
public AbstractProductB createProductB() {
return new ProductB2();
}}
class ProductA1 implements AbstractProductA {
@Override
public void interact (AbstractProductB b) {
System.out.println(this.getClass().getName() + " interacts with " + b.getClass().getName());
}
}
class ProductB1 implements AbstractProductB {
@Override
public void interact (AbstractProductA a) {
System.out.println(this.getClass().getName() + " interacts with " + a.getClass().getName());
}
}
class ProductA2 implements AbstractProductA {
@Override
public void interact(AbstractProductB b) {
System.out.println(this.getClass().getName() + " interacts with " + b.getClass().getName());
}
}
class ProductB2 implements AbstractProductB {
@Override
public void interact(AbstractProductA a) {
System.out.println(this.getClass().getName() + " interacts with " + a.getClass().getName());
}
}
Еще пример
#include <iostream> #include <vector>
// Абстрактные базовые классы всех возможных видов воинов class Infantryman // пехотинец { public: virtual void info() = 0; virtual ~Infantryman() {} };
class Archer //стрелок, лучник { public: virtual void info() = 0; virtual ~Archer() {} };
class Horseman //кавалерист { public: virtual void info() = 0; virtual ~Horseman() {} };
// Конкретные классы всех видов воинов Римской армии class RomanInfantryman: public Infantryman { public: void info() { cout << "RomanInfantryman" << endl; } };
class RomanArcher: public Archer { public: void info() { cout << "RomanArcher" << endl; } };
class RomanHorseman: public Horseman { public: void info() { cout << "RomanHorseman" << endl; } };
// Классы всех видов воинов армии Карфагена class CarthaginianInfantryman: public Infantryman { public: void info() { cout << "CarthaginianInfantryman" << endl; } };
class CarthaginianArcher: public Archer { public: void info() { cout << "CarthaginianArcher" << endl; } };
class CarthaginianHorseman: public Horseman { public: void info() { cout << "CarthaginianHorseman" << endl; } };
// Абстрактная фабрика для производства воинов class ArmyFactory { public: virtual Infantryman* createInfantryman() = 0; virtual Archer* createArcher() = 0; virtual Horseman* createHorseman() = 0; virtual ~ArmyFactory() {} };
// Фабрика для создания воинов Римской армии class RomanArmyFactory: public ArmyFactory { public: Infantryman* createInfantryman() { return new RomanInfantryman; } Archer* createArcher() { return new RomanArcher; } Horseman* createHorseman() { return new RomanHorseman; } };
// Фабрика для создания воинов армии Карфагена class CarthaginianArmyFactory: public ArmyFactory { public: Infantryman* createInfantryman() { return new CarthaginianInfantryman; } Archer* createArcher() { return new CarthaginianArcher; } Horseman* createHorseman() { return new CarthaginianHorseman; } };
// Класс, содержащий всех воинов той или иной армии class Army { public: ~Army() { int i; for(i=0; i<vi.size(); ++i) delete vi[i]; for(i=0; i<va.size(); ++i) delete va[i]; for(i=0; i<vh.size(); ++i) delete vh[i]; } void info() { int i; for(i=0; i<vi.size(); ++i) vi[i]->info(); for(i=0; i<va.size(); ++i) va[i]->info(); for(i=0; i<vh.size(); ++i) vh[i]->info(); } vector<Infantryman*> vi; vector<Archer*> va; vector<Horseman*> vh; };
// Здесь создается армия той или иной стороны class Game { public: Army* createArmy( ArmyFactory& factory ) { Army* p = new Army; p->vi.push_back( factory.createInfantryman()); p->va.push_back( factory.createArcher()); p->vh.push_back( factory.createHorseman()); return p; } };
int main () { Game game; RomanArmyFactory ra_factory; CarthaginianArmyFactory ca_factory;
Army * ra = game.createArmy( ra_factory); Army * ca = game.createArmy( ca_factory); cout << "Roman army:" << endl; ra->info(); cout << "\nCarthaginian army:" << endl; ca->info(); // ... } |
Вывод программы будет следующим:
|
Roman army: RomanInfantryman RomanArcher RomanHorseman
Carthaginian army: CarthaginianInfantryman CarthaginianArcher CarthaginianHorseman
|
