-
Notifications
You must be signed in to change notification settings - Fork 2
ООП Лекция 13. Структурные паттерны.
Структурные паттерны предлагают структурные решения. Это какая-либо декомпозиция классов с использованием схем наследования, включения...
Если одна сущность выполняет несколько ответственностей, надо разделять задачи => проблема дальнейшего развития. В случае если какая-то ответственность меняется, а другая нет, что делать? Надо разделять как в фабричном методе, любой порождающий паттерн надо выделять ответственного за принятия решений. Как быть?
Проблема, с которой мы сталкиваемся - это когда нам надо создавать объекты, и эти объекты в разных местах программы мы используем по-разному. Грубо говоря, один объект выступает в нескольких ролях. Из этого следует:
- Для каждой роли используется свой интерфейс. В принципе, эти интерфейсы могу пересекаться. Но, если мы будем создавать такой класс, мы получим избыточный интерфейс.
- Как правило, эти роли завязаны еще под ответственность. Один и тот же объект будет иметь несколько ответственностей, что с точки зрения ООП очень плохо. Каждый объект должен иметь только одну ответственностей.
Идея: У нас один и тот же объект выполняет несколько ролей, физически это один объект. В разных местах мы работаем с ним по-разному, т.е. разные интерфейсы. Выделить простой класс, а посредники будет представлять нужный класс для работы.
Реализуем понятие или сущность какую-то с простым интерфейсом, а любая работа через посредника идет, вот из диаграммы можно увидеть, что:
-
ConAdapterA
- это одна роль объекта -
ConAdapterB
- это другая роль того же самого объекта и при изменении какой из них, другая не меняется. В разных частях программы по-разному работаем с эти объектом.
Кроме это задачи с разделением ролей он решает еще задачи, есть система используется какую библиотеку, но хотите поменять что-то, но здесь другой интерфейс, и чтобы не переписывать код применяется адаптер.
Примечание: Solution подобный => вырожденный Адаптер
Преимущества:
- Он позволяет нам класс с любым интерфейсом использовать в нашей программе.
- Позволяет не создавать нам классы с несколькими ответственностями. Разносим это по другим классам.
Недостатки:
- Просто не понять без UML.
- Дублирование кода (Кучу классов), нет мертвых классов.
# include <iostream>
# include <memory>
using namespace std;
class Adapter
{
public:
virtual ~Adapter() = default;
virtual void request() = 0;
};
class BaseAdaptee
{
public:
virtual ~BaseAdaptee() = default;
virtual void specificRequest() = 0;
};
class ConAdapter : public Adapter
{
private:
shared_ptr<BaseAdaptee> adaptee;
public:
ConAdapter(shared_ptr<BaseAdaptee> ad) : adaptee(ad) {}
virtual void request() override;
};
class ConAdaptee : public BaseAdaptee
{
public:
virtual void specificRequest() override { cout << "Method ConAdaptee;" << endl; }
};
#pragma region Methods
void ConAdapter::request()
{
cout << "Adapter: ";
if (adaptee)
{
adaptee->specificRequest();
}
else
{
cout << "Empty!" << endl;
}
}
#pragma endregion
int main()
{
shared_ptr<BaseAdaptee> adaptee = make_shared<ConAdaptee>();
shared_ptr<Adapter> adapter = make_shared<ConAdapter>(adaptee);
adapter->request();
}
Задача: избавиться от дублирования кода и большой иерархии
Декораторов может быть много
Можем продекорировать как одну сущность так и другую. Работать с декоратором будем работать как с компонентом, декоратор входит в общую иерархию
Возможно изменение объекта во время выполнения
Минусы
- Долго выполняться
Их очень много, рассмотрим только основную часть