Абстрактная фабрика (шаблон проектирования) (GQvmjgtmugx sgQjntg (ogQlku hjkytmnjkfgunx))
Перейти к навигации
Перейти к поиску
Абстрактная фабрика | |
---|---|
Abstract factory | |
Тип | порождающий |
Назначение | Предоставляет интерфейс для создания семейств взаимосвязанных или взаимозависимых объектов, не специфицируя их конкретных классов. |
Структура | |
Применяется в случаях |
|
Плюсы |
|
Минусы |
|
Описан в Design Patterns | Да |
Абстрактная фабрика (англ. Abstract factory) — порождающий шаблон проектирования, предоставляет интерфейс для создания семейств взаимосвязанных или взаимозависимых объектов, не специфицируя их конкретных классов. Шаблон реализуется созданием абстрактного класса Factory, который представляет собой интерфейс для создания компонентов системы (например, для оконного интерфейса он может создавать окна и кнопки). Затем пишутся классы, реализующие этот интерфейс[2].
Назначение
[править | править код]Предоставляет интерфейс для создания семейств взаимосвязанных или взаимозависимых объектов, не специфицируя их конкретных классов.
Реализация
[править | править код]Плюсы
[править | править код]- изолирует конкретные классы;
- упрощает замену семейств продуктов;
- гарантирует сочетаемость продуктов.
Минусы
[править | править код]- сложно добавить поддержку нового вида продуктов.
Применение
[править | править код]- Система не должна зависеть от того, как создаются, компонуются и представляются входящие в неё объекты.
- Входящие в семейство взаимосвязанные объекты должны использоваться вместе и вам необходимо обеспечить выполнение этого ограничения.
- Система должна конфигурироваться одним из семейств составляющих её объектов.
- Требуется предоставить библиотеку объектов, раскрывая только их интерфейсы, но не реализацию.
Примеры
[править | править код]Пример на Kotlin
[править | править код]Исходный текст на языке Kotlin
import kotlin.random.Random
// next interfaces are products of abstract factories
interface Executor
interface Legislator
interface Judge
// just wrapper for government
data class Governor(
val name: String,
val executor: Executor,
val legislator: Legislator,
val judge: Judge
) {
fun work() {
println("Government $name is working!")
println("Legislator $legislator set the Law")
println("Executor $executor catch all criminals by the legislator laws")
println("Judge $judge has sentenced all criminals to punishment")
}
}
// abstract factory interface
interface GovernmentFactory {
fun createExecutor(): Executor
fun createJudge(): Judge
fun createLegislator(): Legislator
/**
* Template Method Pattern
*/
fun createGovernment(name: String): Governor {
return Governor(
name,
createExecutor(),
createLegislator(),
createJudge()
)
}
}
data class Monarch(
val name: String
) : Judge, Executor, Legislator
// implementation of abstract factory
object RussianMonarchyFactory : GovernmentFactory {
private val ivanGrozny = Monarch("Иван Грозный")
override fun createExecutor(): Executor {
return ivanGrozny
}
override fun createJudge(): Judge {
return ivanGrozny
}
override fun createLegislator(): Legislator {
return ivanGrozny
}
}
data class PresidentCandidate(
val name: String,
private val myJudgeGuy: Judge
) : Executor {
fun setJudge(): Judge {
return myJudgeGuy
}
}
private val CONGRESS_MEMBER_COUNT = 535
data class Congress(
val republicans: Int,
val democrats: Int = CONGRESS_MEMBER_COUNT - republicans
) : Legislator
class AmericanElectorate(
private val presidentCandidates: List<PresidentCandidate>
) {
fun choosePresident(): PresidentCandidate {
return presidentCandidates.random()// here should be logic of choosing the president
}
fun chooseParliament(): Legislator {
val delta = Random.nextInt(15)
return Congress(CONGRESS_MEMBER_COUNT / 2 - delta)
}
}
// implementation of abstract factory
class PresidentRepublicFactory(
private val electorate: AmericanElectorate,
private var currentPresident: PresidentCandidate
) : GovernmentFactory {
override fun createExecutor(): Executor {
currentPresident = electorate.choosePresident()
return currentPresident
}
override fun createJudge(): Judge {
return currentPresident.setJudge()
}
override fun createLegislator(): Legislator {
return electorate.chooseParliament()
}
}
data class ElectivePerson(
val name: String
): Judge, Executor
data class Parliament(
val description: String, // left, centrist or right parties
val president: ElectivePerson,
val judge: Judge
): Legislator
class EuropeanElectorate(
val people: List<ElectivePerson>
) {
fun chooseParliament(): Parliament {
return Parliament(
listOf("left", "centrist", "right").random(),
people.random(),
people.random()
)
}
}
// implementation of abstract factory
class ParliamentRepublicFactory(
private val electorate: EuropeanElectorate,
private var electedParliament: Parliament
): GovernmentFactory {
override fun createExecutor(): Executor {
return electedParliament.president
}
override fun createJudge(): Judge {
return electedParliament.judge
}
override fun createLegislator(): Legislator {
electedParliament = electorate.chooseParliament()
return electedParliament
}
/**
* should be overridden because we should select parliament firstly
*/
override fun createGovernment(name: String): Governor {
val parliament = createLegislator()
return Governor(name, createExecutor(), parliament, createJudge())
}
}
fun main() {
val biden = PresidentCandidate("Biden", ElectivePerson("Kamalla Harris"))
val americanElectorate = AmericanElectorate(listOf(
biden,
PresidentCandidate("Trump", ElectivePerson("Obama"))
))
val europeanElectorate = EuropeanElectorate(listOf(
ElectivePerson("Boris Johnson"),
ElectivePerson("Princess Diane"),
ElectivePerson("Jack Shirak"),
ElectivePerson("Viktor Orban"),
ElectivePerson("Floda Reltih"),
ElectivePerson("Green Sky"),
))
//set abstract factory of governments to countries
mapOf(
"Rus" to RussianMonarchyFactory,
"USA" to PresidentRepublicFactory(americanElectorate, biden),
"Deutschland" to ParliamentRepublicFactory(europeanElectorate, Parliament("Communists",
ElectivePerson("Climate Liar"),
ElectivePerson("War Criminal"),
))
).map { (country, govFactory) ->
govFactory.createGovernment(country) // create governments
}.forEach {
it.work() // enforce them to work
}
}
Пример на Swift
[править | править код]Исходный текст на языке Swift
//: Playground - noun: a place where people can play
/// <summary>
/// Класс абстрактной фабрики
/// </summary>
protocol AbstractFactory {
func createProductA() -> AbstractProductA
func createProductB() -> AbstractProductB
}
/// <summary>
/// Класс фабрики № 1
/// </summary>
class ConcreteFactory1: AbstractFactory {
public func createProductA() -> AbstractProductA {
return ProductA1()
}
public func createProductB() -> AbstractProductB {
return ProductB1()
}
}
/// <summary>
/// Класс фабрики № 2
/// </summary>
class ConcreteFactory2 : AbstractFactory {
public func createProductA() -> AbstractProductA {
return ProductA2()
}
public func createProductB() -> AbstractProductB {
return ProductB2()
}
}
/// <summary>
/// Абстрактный класс продукта А
/// </summary>
protocol AbstractProductA {}
//
/// <summary>
/// Абстрактный класс продукта В
/// </summary>
protocol AbstractProductB {
func interact(a: AbstractProductA)
}
/// <summary>
/// Первый класс продукта типа А
/// </summary>
class ProductA1 : AbstractProductA {}
/// <summary>
/// Первый класс продукта типа В
/// </summary>
class ProductB1 : AbstractProductB {
public func interact(a: AbstractProductA) {
print("\(type(of:self)) interacts with \(type(of: a.self))")
}
}
/// <summary>
/// Второй класс продукта типа А
/// </summary>
class ProductA2 : AbstractProductA {}
/// <summary>
/// Второй класс продукта типа В
/// </summary>
class ProductB2 : AbstractProductB {
public func interact(a: AbstractProductA) {
print("\(type(of:self)) interacts with \(type(of: a.self))")
}
}
/// <summary>
/// Класс клиента, в котором происходит взаимодействие между объектами
/// </summary>
class Client {
private let _abstractProductA: AbstractProductA
private let _abstractProductB: AbstractProductB
// Конструктор
public init(factory: AbstractFactory) {
_abstractProductB = factory.createProductB();
_abstractProductA = factory.createProductA();
}
public func run() {
_abstractProductB.interact(a: _abstractProductA)
}
}
/// <summary>
/// Точка входа в приложение
/// </summary>
// Вызов абстрактной фабрики № 1
let factory1 = ConcreteFactory1()
let client1 = Client(factory: factory1)
client1.run()
// Вызов абстрактной фабрики № 2
let factory2 = ConcreteFactory2()
let client2 = Client(factory: factory2)
client2.run()
Пример на C#[3]
[править | править код]Исходный код на языке C Sharp
using System;
namespace DoFactory.GangOfFour.Abstract.Structural
{
class MainApp
{
public static void Main()
{
AbstractFactory factory1 = new ConcreteFactory1();
Client client1 = new Client(factory1);
client1.Run();
AbstractFactory factory2 = new ConcreteFactory2();
Client client2 = new Client(factory2);
client2.Run();
Console.ReadKey();
}
}
abstract class AbstractFactory
{
public abstract AbstractProductA CreateProductA();
public abstract AbstractProductB CreateProductB();
}
class ConcreteFactory1 : AbstractFactory
{
public override AbstractProductA CreateProductA()
{
return new ProductA1();
}
public override AbstractProductB CreateProductB()
{
return new ProductB1();
}
}
class ConcreteFactory2 : AbstractFactory
{
public override AbstractProductA CreateProductA()
{
return new ProductA2();
}
public override AbstractProductB CreateProductB()
{
return new ProductB2();
}
}
abstract class AbstractProductA
{
}
abstract class AbstractProductB
{
public abstract void Interact(AbstractProductA a);
}
class ProductA1 : AbstractProductA
{
}
class ProductB1 : AbstractProductB
{
public override void Interact(AbstractProductA a)
{
Console.WriteLine(this.GetType().Name +
" interacts with " + a.GetType().Name);
}
}
class ProductA2 : AbstractProductA
{
}
class ProductB2 : AbstractProductB
{
public override void Interact(AbstractProductA a)
{
Console.WriteLine(this.GetType().Name +
" interacts with " + a.GetType().Name);
}
}
class Client
{
private AbstractProductA _abstractProductA;
private AbstractProductB _abstractProductB;
public Client(AbstractFactory factory)
{
_abstractProductB = factory.CreateProductB();
_abstractProductA = factory.CreateProductA();
}
public void Run()
{
_abstractProductB.Interact(_abstractProductA);
}
}
}
Пример на Java
[править | править код]Исходный текст на языке Java
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());
}
}
Пример на PHP5
[править | править код]Исходный текст на языке PHP5
interface IHead
{
public function drawHead($x, $y);
}
class RedHead implements IHead
{
public function drawHead($x, $y) {
echo 'Your red head in axis x = ' . $x . ' and axis y = ' . $y . '</ br>' . PHP_EOL;
}
}
class WhiteHead implements IHead
{
public function drawHead($x, $y) {
echo 'Your white head in axis x = ' . $x . ' and axis y = ' . $y . '</ br>' . PHP_EOL;
}
}
interface IBody
{
public function drawBody($x, $y);
}
class RedBody implements IBody
{
public function drawBody($x, $y) {
echo 'Your red body in axis x = ' . $x . ' and axis y = ' . $y . '</ br>' . PHP_EOL;
}
}
class WhiteBody implements IBody
{
public function drawBody($x, $y) {
echo 'Your white body in axis x = ' . $x . ' and axis y = ' . $y . '</ br>' . PHP_EOL;
}
}
/**
* Interface ISnowman - this is abstract factory
*/
interface ISnowman
{
public function drawHead($x, $y);
public function drawBody($x, $y);
}
/**
* Class WhiteSnowman - concrete factory
*/
class WhiteSnowman implements ISnowman
{
protected $head;
protected $body;
public function __construct() {
$this->head = new WhiteHead();
$this->body = new WhiteBody();
}
public function drawHead($x, $y) {
$this->head->drawHead($x, $y);
}
public function drawBody($x, $y) {
$this->body->drawBody($x, $y);
}
}
/**
* Class RedSnowman - concrete factory
*/
class RedSnowman implements ISnowman
{
protected $head;
protected $body;
public function __construct() {
$this->head = new RedHead();
$this->body = new RedBody();
}
public function drawHead($x, $y) {
$this->head->drawHead($x, $y);
}
public function drawBody($x, $y) {
$this->body->drawBody($x, $y);
}
}
function snowman(ISnowman $snowman) {
$snowman->drawHead(1,1);
$snowman->drawBody(1,2);
}
$typeSnowman = 'red';
// мы выбираем тип семейства в начале кода
if($typeSnowman == 'red')
$snowman = new RedSnowman();
else
$snowman = new WhiteSnowman();
snowman($snowman);
Пример на Python
[править | править код]Исходный текст на языке Python
from abc import ABCMeta, abstractmethod
class Beer(metaclass=ABCMeta):
pass
class Snack(metaclass=ABCMeta):
@abstractmethod
def interact(self, beer: Beer) -> None:
pass
class AbstractShop(metaclass=ABCMeta):
@abstractmethod
def buy_beer(self) -> Beer:
pass
@abstractmethod
def buy_snack(self) -> Snack:
pass
class Tuborg(Beer):
pass
class Staropramen(Beer):
pass
class Peanuts(Snack):
def interact(self, beer: Beer) -> None:
print('Мы выпили по бутылке пива {} и закусили его арахисом'.format(
beer.__class__.__name__))
class Chips(Snack):
def interact(self, beer: Beer) -> None:
print('Мы выпили несколько банок пива {} и съели пачку чипсов'.format(
beer.__class__.__name__))
class ExpensiveShop(AbstractShop):
def buy_beer(self) -> Beer:
return Tuborg()
def buy_snack(self) -> Snack:
return Peanuts()
class CheapShop(AbstractShop):
def buy_beer(self) -> Beer:
return Staropramen()
def buy_snack(self) -> Snack:
return Chips()
if __name__ == '__main__':
expensive_shop = ExpensiveShop()
cheap_shop = CheapShop()
print('OUTPUT:')
beer = expensive_shop.buy_beer()
snack = cheap_shop.buy_snack()
snack.interact(beer)
beer = cheap_shop.buy_beer()
snack = expensive_shop.buy_snack()
snack.interact(beer)
'''
OUTPUT:
Мы выпили несколько банок пива Tuborg и съели пачку чипсов
Мы выпили по бутылке пива Staropramen и закусили его арахисом
'''
Пример на Scala
[править | править код]Исходный текст на языке Scala
abstract class AbstractTerrestrialAnimal {
def walk: String
}
abstract class AbstractWaterAnimal {
def swim: String
}
abstract class AbstractZoo {
def getCity: String
def getTerrestrialAnimal: AbstractTerrestrialAnimal
def getWaterAnimal: AbstractWaterAnimal
}
class Wolverine extends AbstractTerrestrialAnimal {
override def walk: String = "Wolverine is walking"
}
class HoneyBadger extends AbstractTerrestrialAnimal {
override def walk: String = "Honey badger is walking"
}
class Walrus extends AbstractWaterAnimal {
override def swim: String = "Walrus is swimming"
}
class SeaLion extends AbstractWaterAnimal {
override def swim: String = "Sea lion is swimming"
}
class MunichZoo extends AbstractZoo {
override def getCity: String = "Munich"
override def getTerrestrialAnimal: AbstractTerrestrialAnimal = new Wolverine
override def getWaterAnimal: AbstractWaterAnimal = new Walrus
}
class CapeTownZoo extends AbstractZoo {
override def getCity: String = "CapeTown"
override def getTerrestrialAnimal: AbstractTerrestrialAnimal = new HoneyBadger
override def getWaterAnimal: AbstractWaterAnimal = new SeaLion
}
object AbstractFactoryTest {
private def testZoo(zoo: AbstractZoo): Unit = {
println(s"Zoo of ${zoo.getCity}:")
println(zoo.getTerrestrialAnimal.walk)
println(zoo.getWaterAnimal.swim)
}
def main(args: Array[String]) Unit = {
testZoo(new CapeTownZoo)
testZoo(new MunichZoo)
}
}
Пример на Go
[править | править код]Исходный текст на языке Go
package main
import "fmt"
type Unit interface {
What() string
}
type Action interface {
What() string
}
type Place interface {
What() string
}
type TransportFactory interface {
MakeUnit() Unit
MakeAction() Action
MakePlace() Place
}
type Car struct{}
func (self Car) What() string {
return "car"
}
type Ride struct{}
func (self Ride) What() string {
return "ride"
}
type Road struct{}
func (self Road) What() string {
return "road"
}
type LandTransportFactory struct{}
func (self LandTransportFactory) MakeUnit() Unit {
return &Car{}
}
func (self LandTransportFactory) MakeAction() Action {
return &Ride{}
}
func (self LandTransportFactory) MakePlace() Place {
return &Road{}
}
type Boat struct{}
func (self Boat) What() string {
return "boat"
}
type Sail struct{}
func (self Sail) What() string {
return "sail"
}
type Sea struct{}
func (self Sea) What() string {
return "sea"
}
type SeaTransportFactory struct{}
func (self SeaTransportFactory) MakeUnit() Unit {
return &Boat{}
}
func (self SeaTransportFactory) MakeAction() Action {
return &Sail{}
}
func (self SeaTransportFactory) MakePlace() Place {
return &Sea{}
}
func action(factory TransportFactory) {
unit := factory.MakeUnit()
unit_action := factory.MakeAction()
place := factory.MakePlace()
fmt.Printf("The %s %ss over the %s.\n",
unit.What(), unit_action.What(), place.What())
}
func main() {
action(&LandTransportFactory{})
action(&SeaTransportFactory{})
}
Вывод
The car rides over the road. The boat sails over the sea.
Пример на Ruby
[править | править код]Исходный текст на языке Ruby
module AbstractFactoryPattern
# Provide an interface for creating families of related or dependent objects without specifying their concrete classes
# Abstract Factory
class WarriorFactory
def create_knight
raise NotImplementedError
end
def create_archer
raise NotImplementedError
end
end
# Concrete Factory
class OrcWarriorFactory < WarriorFactory
def create_knight
OrcKnight.new
end
def create_archer
OrcArcher.new
end
end
# Concrete Factory
class ElfWarriorFactory < WarriorFactory
def create_knight
ElfKnight.new
end
def create_archer
ElfArcher.new
end
end
# Abstract Product
class Knight
def inspect
self.class.name.split('::').last
end
end
# Abstract Product
class Archer
def inspect
self.class.name.split('::').last
end
end
# Product
class OrcKnight < Knight
end
# Product
class ElfKnight < Knight
end
# Product
class OrcArcher < Archer
end
# Product
class ElfArcher < Archer
end
# Client
class Army
def initialize(factory)
@knights = []
3.times { @knights << factory.create_knight }
@archers = []
3.times { @archers << factory.create_archer }
end
def inspect
"Knights #{@knights.map(&:inspect)} Archers #{@archers.map(&:inspect)}"
end
end
def self.run
orcs = Army.new(OrcWarriorFactory.new)
puts "Orcs army: #{orcs.inspect}"
elves = Army.new(ElfWarriorFactory.new)
puts "Elves army: #{elves.inspect}"
end
end
AbstractFactoryPattern.run
# Orcs army: Knights ["OrcKnight", "OrcKnight", "OrcKnight"] Archers ["OrcArcher", "OrcArcher", "OrcArcher"]
# Elves army: Knights ["ElfKnight", "ElfKnight", "ElfKnight"] Archers ["ElfArcher", "ElfArcher", "ElfArcher"]
Литература
[править | править код]- Э. Гамма, Р. Хелм, Р. Джонсон, Дж. Влиссидес. Приёмы объектно-ориентированного проектирования. Паттерны проектирования = Design Patterns: Elements of Reusable Object-Oriented Software. — СПб.: «Питер», 2007. — С. 366. — ISBN 978-5-469-01136-1. (также ISBN 5-272-00355-1)
Ссылки
[править | править код]- Паттерн Abstract Factory (абстрактная фабрика) — назначение, описание, реализация на C++, достоинства и недостатки
Примечания
[править | править код]- ↑ Паттерн Abstract Factory . Дата обращения: 14 июня 2013. Архивировано 14 июня 2013 года.
- ↑ Порождающие шаблоны: Абстрактная фабрика (Abstract factory) . Дата обращения: 14 июня 2013. Архивировано 14 июня 2013 года.
- ↑ Abstract Factory .NET Design Pattern in C# and VB - dofactory.com . www.dofactory.com. Дата обращения: 3 марта 2016. Архивировано 3 марта 2016 года.