Мабуть, всі чули таке поняття як дизайн-патерни (design patterns). Це свого роду шаблони, призначені для проектування програм. Звісно, їх знати не обов'язково, але якщо ви хочете стати гарним програмістом та писати якісний код, без патернів не обійтись. Такі шаблони перевірені багатьма професіоналами та є ефективними для розробки програм, та для збереження часу програміста.
Перш, ніж перейти безпосередньо до теми статті, а саме до патерну «Абстрактна фабрика», варто знати наступне:
Дизайн-патернів є 23 і діляться вони на 3 групи:
- Породжуючі – спрощують створення об'єктів;
- Структурні – описують зв'язки між класами та формують їхню структуру;
- Поведінкові – визначають поведінку класів, об'єктів та процесу виконання в цілому.
Деякі патерни не є легкими для сприйняття, тож будьте готові до труднощів.
Абстрактна фабрика (Abstract factory)
Абстрактна фабрика – це породжуючий патерн.
Призначення: створення об'єктів, , які належать до однієї групи, шляхом абстрагування.
Для того, щоби краще зрозуміти що це, розглянемо наочний приклад.
Припустимо, у вас є своя рок-група, в якій є кілька учасників. Один з них грає на акустичній гітарі, другий – на електрогітарі, а третій відповідно від бажання на електричних барабанах або на акустичних.
Значить вам необхідно дати кожному музиканту той музичний інструмент, який йому потрібно. Це означає, що ви – абстрактна фабрика, бо можете надати потрібний інструмент, не зважаючи який він – електричний чи акустичний.
Коли гітарист просить акустичну гітару, ви надаєте йому її. Отже, електричний інструмент і акустичний – це вже не абстракція, а конкретні фабрики, які містять конкретні інструменти – електричні та акустичні.
Розглянемо код:
#pragma once
class Drum
{
public:
Drum();
~Drum();
};
#pragma once
class Guitar
{
public:
Guitar();
~Guitar();
};
Створюємо два класи – Drum
та Guitar
. Ці класи представлені для загального прикладу і не мають жодних членів даних та методів.
Далі створимо клас MusicInstruments
:
#pragma once
#include "stdafx.h"
#include "Drum.h"
#include "Guitar.h"
class MusicInstruments
{
public:
virtual Drum getDrum() = 0;
virtual Guitar getGuitar() = 0;
};
Цей клас і є абстрактною фабрикою, яка повертатиме певний тип інструменту за допомогою функцій getDrum()
та getGuitar()
. Ці функції є віртуальними, відповідно їхня реалізація знаходитиметься в похідних класах, а сам клас MusicInstruments
– абстрактний клас.
Створимо два похідні класи Acoustic
та Electric
:
Acoustic.h
#pragma once
#include "stdafx.h"
#include "MusicInstruments.h"
class Acoustic : public MusicInstruments
{
public:
Acoustic();
~Acoustic();
Drum getDrum();
Guitar getGuitar();
};
Acoustic.cpp
#include "stdafx.h"
#include "Acoustic.h"
Acoustic::Acoustic()
{
}
Acoustic::~Acoustic()
{
}
Drum Acoustic::getDrum()
{
std::cout << "Gotten an acoustic drum" << std::endl;
return Drum();
}
Guitar Acoustic::getGuitar()
{
std::cout << "Gotten an acoustic guitar" << std::endl;
return Guitar();
}
Electric.h
#pragma once
#include "stdafx.h"
#include "MusicInstruments.h"
class Electric : public MusicInstruments
{
public:
Electric();
~Electric();
Drum getDrum();
Guitar getGuitar();
};
Electric.cpp
#include "stdafx.h"
#include "Electric.h"
Electric::Electric()
{
}
Electric::~Electric()
{
}
Drum Electric::getDrum()
{
std::cout << "Gotten an electric drum" << std::endl;
return Drum();
}
Guitar Electric::getGuitar()
{
std::cout << "Gotten an electric guitar" << std::endl;
return Guitar();
}
Дані класи похідні від класу MusicInstruments
і в них реалізовані функції getDrum()
та getGuitar()
в залежності від того який клас ми використовуємо.
Якщо Acoustic
, то повертаємо акустичні інструменти, а якщо Electric
– електричні. Таким чином класи Acoustic
та Electric
є конкретними фабриками, оскільки повертають конкретний тип інструменту.
Ці функції створюють об'єкт інструмента та повертають його. В реальних прикладах, там задаються певні атрибути для об'єктів у відповідності з конкретною фабрикою, в якій вони створюються.
Використується цей патерн так:
int main()
{
MusicInstruments* mie = new Electric(); // створити об'єкт електричного інструменту
Drum drum = mie->getDrum(); // отримати електричний барабан
Guitar guitar = mie->getGuitar(); // та електрогітару
MusicInstruments* mia = new Acoustic(); // створити акустичний інструмент
Drum drum2 = mia->getDrum(); // отримати акустичний барабан
Guitar guitar2 = mia->getGuitar(); // та гітару
return 0;
}
Звертаючись до абстрактної фабрики, зазначаємо що нам потрібен електричний інструмент, який знаходиться в конкретній фабриці.
Electric
:
MusicInstruments* mie = new Electric();
Після цього вказуємо який саме електричний інструмент потрібен:
Drum drum = mie->getDrum(); // отримати електричний барабан
Guitar guitar = mie->getGuitar(); // та електрогітару
Підсумки
Абстрактна фабрика дозволяє створити об'єкти однієї групи без зазначення їхніх конкретних класів.
Алгоритм створення реалізації такого патерна можна описати наступним чином:
- Створити класи, об'єкти яких є сімейством, що необхідно розділити на фабриці (у прикладах це класи Drum та Guitar);
- Створити абстрактний клас (абстрактну фабрику) з чистими віртуальними функціями, які повертатимуть конкретний об'єкт з конкретної фабрики (в прикладі це клас MusicInstruments);
- Створити конкретні фабрики – класи, що успадковані від абстрактного та в яких реалізовані чисті віртуальні функції, що повертають конкретний об'єкт (як Electric та Acoustic);
- Отримати потрібний об'єкт.
Завантажити вихідний код можна на GitHub.
Ще немає коментарів