Абстрактная фабрика (шаблон проектирования): различия между версиями
[непроверенная версия] | [непроверенная версия] |
Строка 903: | Строка 903: | ||
End Sub |
End Sub |
||
End Class |
End Class |
||
</source> |
|||
}} |
|||
=== Пример Ruby === |
|||
{{Hider_hiding |
|||
| title = Исходный текст на языке [[Ruby]] |
|||
| content = |
|||
<source lang="Ruby"> |
|||
class WinFactory |
|||
def create_button |
|||
WinButton.new |
|||
end |
|||
end |
|||
class LinFactory |
|||
def create_button |
|||
LinButton.new |
|||
end |
|||
end |
|||
class Button |
|||
attr_accessor :caption |
|||
end |
|||
class WinButton < Button |
|||
def render |
|||
puts "I`m WinButton #@caption" |
|||
end |
|||
end |
|||
class LinButton < Button |
|||
def render |
|||
puts "I`m LinButton #@caption" |
|||
end |
|||
end |
|||
class Application |
|||
def initialize(factory) |
|||
button = factory.create_button |
|||
button.caption = 'Start' |
|||
button.render |
|||
end |
|||
end |
|||
class ApplicationRunner |
|||
def self.run |
|||
Application.new(self.createOsSpecificFactory) |
|||
end |
|||
def self.createOsSpecificFactory |
|||
if RUBY_PLATFORM.downcase.include?("mswin") |
|||
WinFactory.new |
|||
else |
|||
LinFactory.new |
|||
end |
|||
end |
|||
end |
|||
ApplicationRunner.run |
|||
</source> |
</source> |
||
}} |
}} |
Версия от 12:17, 17 августа 2011
Абстрактная фабрика | |
---|---|
Abstract factory | |
Тип | порождающий |
Описан в Design Patterns | Да |
Абстрактная фабрика (англ. Abstract factory) — порождающий шаблон проектирования, позволяющий изменять поведение системы, варьируя создаваемые объекты, при этом сохраняя интерфейсы. Он позволяет создавать целые группы взаимосвязанных объектов, которые, будучи созданными одной фабрикой, реализуют общее поведение. Шаблон реализуется созданием абстрактного класса Factory, который представляет собой интерфейс для создания компонентов системы (например, для оконного интерфейса он может создавать окна и кнопки). Затем пишутся наследующиеся от него классы, реализующие этот интерфейс.
Цель
Предоставляет интерфейс для создания семейств взаимосвязанных или взаимозависимых объектов, не специфицируя их конкретных классов.
Плюсы
- изолирует конкретные классы;
- упрощает замену семейств продуктов;
- гарантирует сочетаемость продуктов.
Минусы
- сложно добавить поддержку нового вида продуктов.
Применимость
- Система не должна зависеть от того, как создаются, компонуются и представляются входящие в нее объекты.
- Входящие в семейство взаимосвязанные объекты должны использоваться вместе и вам необходимо обеспечить выполнение этого ограничения.
- Система должна конфигурироваться одним из семейств составляющих ее объектов.
- Требуется предоставить библиотеку объектов, раскрывая только их интерфейсы, но не реализацию.
Пример Java
public abstract class FinancialToolsFactory {
public abstract TaxProcessor createTaxProcessor();
public abstract ShipFeeProcessor createShipFeeProcessor();
}
public abstract class ShipFeeProcessor {
abstract void calculateShipFee(Order order);
}
public abstract class TaxProcessor {
abstract void calculateTaxes(Order order);
}
// Factories
public class CanadaFinancialToolsFactory extends FinancialToolsFactory {
public TaxProcessor createTaxProcessor() {
return new CanadaTaxProcessor();
}
public ShipFeeProcessor createShipFeeProcessor() {
return new CanadaShipFeeProcessor();
}
}
public class EuropeFinancialToolsFactory extends FinancialToolsFactory {
public TaxProcessor createTaxProcessor() {
return new EuropeTaxProcessor();
}
public ShipFeeProcessor createShipFeeProcessor() {
return new EuropeShipFeeProcessor();
}
}
// Products
public class EuropeShipFeeProcessor extends ShipFeeProcessor {
public void calculateShipFee(Order order) {
// insert here Europe specific ship fee calculation
}
}
public class CanadaShipFeeProcessor extends ShipFeeProcessor {
public void calculateShipFee(Order order) {
// insert here Canada specific ship fee calculation
}
}
public class EuropeTaxProcessor extends TaxProcessor {
public void calculateTaxes(Order order) {
// insert here Europe specific taxt calculation
}
}
public class CanadaTaxProcessor extends TaxProcessor {
public void calculateTaxes(Order order) {
// insert here Canada specific taxt calculation
}
}
// Client
public class OrderProcessor {
private TaxProcessor taxProcessor;
private ShipFeeProcessor shipFeeProcessor;
public OrderProcessor(FinancialToolsFactory factory) {
taxProcessor = factory.createTaxProcessor();
shipFeeProcessor = factory.createShipFeeProcessor();
}
public void processOrder (Order order) {
// ....
taxProcessor.calculateTaxes(order);
shipFeeProcessor.calculateShipFee(order);
// ....
}
}
// Integration with the overall application
enum CountryCode {
EU,
CA
}
public class Application {
public static void main(final String... args) {
// .....
final CountryCode countryCode = CountryCode.EU;
final FinancialToolsFactory factory;
switch (countryCode) {
case EU:
factory = new EuropeFinancialToolsFactory();
break;
case CA:
factory = new CanadaFinancialToolsFactory();
break;
default:
throw new IllegalStateException();
}
final OrderProcessor orderProcessor = new OrderProcessor(factory);
orderProcessor.processOrder(new Order());
}
}
Пример С++
#include <iostream>
// AbstractProductA
class ICar
{
public:
virtual void printName() = 0;
};
// ConcreteProductA1
class Ford : public ICar
{
public:
virtual void printName()
{
std::cout << "Ford" << std::endl;
}
};
// ConcreteProductA2
class Toyota : public ICar
{
public:
virtual void printName()
{
std::cout << "Toyota" << std::endl;
}
};
// AbstractProductB
class IEngine
{
public:
virtual void printPower() = 0;
};
// ConcreteProductB1
class FordEngine : public IEngine
{
public:
virtual void printPower()
{
std::cout << "Ford Engine 4.4" << std::endl;
}
};
// ConcreteProductB2
class ToyotaEngine : public IEngine
{
public:
virtual void printPower()
{
std::cout << "Toyota Engine 3.2" << std::endl;
}
};
// AbstractFactory
class ICarFactory
{
public:
virtual ICar* createCar() = 0;
virtual IEngine* createEngine() = 0;
};
// ConcreteFactory1
class FordFactory : public ICarFactory
{
public:
// from ICarFactory
virtual ICar* createCar()
{
return new Ford();
}
virtual IEngine* createEngine()
{
return new FordEngine();
}
};
// ConcreteFactory2
class ToyotaFactory : public ICarFactory
{
public:
// from ICarFactory
virtual ICar* createCar()
{
return new Toyota();
}
virtual IEngine* createEngine()
{
return new ToyotaEngine();
}
};
void use(ICarFactory* f)
{
ICar* myCar = f->createCar();
IEngine* myEngine = f->createEngine();
myCar->printName();
myEngine->printPower();
delete myCar;
delete myEngine;
}
int main()
{
ToyotaFactory toyotaFactory;
FordFactory fordFactory;
use (&toyotaFactory);
use (&fordFactory);
return 0;
}
Пример С#
using System;
class MainApp
{
public static void Main()
{
// Abstract factory #1
AbstractFactory factory1 = new ConcreteFactory1();
Client c1 = new Client(factory1);
c1.Run();
// Abstract factory #2
AbstractFactory factory2 = new ConcreteFactory2();
Client c2 = new Client(factory2);
c2.Run();
// Wait for user input
Console.Read();
}
}
// "AbstractFactory"
abstract class AbstractFactory
{
public abstract AbstractProductA CreateProductA();
public abstract AbstractProductB CreateProductB();
}
// "ConcreteFactory1"
class ConcreteFactory1 : AbstractFactory
{
public override AbstractProductA CreateProductA()
{
return new ProductA1();
}
public override AbstractProductB CreateProductB()
{
return new ProductB1();
}
}
// "ConcreteFactory2"
class ConcreteFactory2 : AbstractFactory
{
public override AbstractProductA CreateProductA()
{
return new ProductA2();
}
public override AbstractProductB CreateProductB()
{
return new ProductB2();
}
}
// "AbstractProductA"
abstract class AbstractProductA
{
}
// "AbstractProductB"
abstract class AbstractProductB
{
public abstract void Interact(AbstractProductA a);
}
// "ProductA1"
class ProductA1 : AbstractProductA
{
}
// "ProductB1"
class ProductB1 : AbstractProductB
{
public override void Interact(AbstractProductA a)
{
Console.WriteLine(this.GetType().Name +
" interacts with " + a.GetType().Name);
}
}
// "ProductA2"
class ProductA2 : AbstractProductA
{
}
// "ProductB2"
class ProductB2 : AbstractProductB
{
public override void Interact(AbstractProductA a)
{
Console.WriteLine(this.GetType().Name +
" interacts with " + a.GetType().Name);
}
}
// "Client" - the interaction environment of the products
class Client
{
private AbstractProductA abstractProductA;
private AbstractProductB abstractProductB;
// Constructor
public Client(AbstractFactory factory)
{
abstractProductB = factory.CreateProductB();
abstractProductA = factory.CreateProductA();
}
public void Run()
{
abstractProductB.Interact(abstractProductA);
}
}
Пример JavaScript
// AbstractProducts
// создаем абстрактные классы продуктов
// AbstractProductA
// "интерфейс" пошлины за перевозку
function ShipFeeProcessor() {
this.calculate = function(order) { };
}
// AbstractProductB
// "интерфейс" налога
function TaxProcessor() {
this.calculate = function(order) { };
}
// Products
// создаем реализацию абстрактных классов
// Product A1
// класс для расчета пошлины за перевозку для Европы
function EuropeShipFeeProcessor() {
this.calculate = function(order) {
// перегрузка метода calculate ShipFeeProcessor
return 11 + order;
};
}
EuropeShipFeeProcessor.prototype = new ShipFeeProcessor();
EuropeShipFeeProcessor.prototype.constructor = EuropeShipFeeProcessor;
// Product A2
// класс для расчета пошлины за перевозку для Канады
function CanadaShipFeeProcessor() {
this.calculate = function(order) {
// перегрузка метода calculate ShipFeeProcessor
return 12 + order;
};
}
CanadaShipFeeProcessor.prototype = new ShipFeeProcessor();
CanadaShipFeeProcessor.prototype.constructor = CanadaShipFeeProcessor;
// Product B1
// класс для расчета налогов для Европы
function EuropeTaxProcessor() {
this.calculate = function(order) {
// перегрузка метода calculate TaxProcessor
return 21 + order;
};
}
EuropeTaxProcessor.prototype = new TaxProcessor();
EuropeTaxProcessor.prototype.constructor = EuropeTaxProcessor;
// Product B2
// класс для расчета налогов для Канады
function CanadaTaxProcessor() {
this.calculate = function(order) {
// перегрузка метода calculate TaxProcessor
return 22 + order;
};
}
CanadaTaxProcessor.prototype = new TaxProcessor();
CanadaTaxProcessor.prototype.constructor = CanadaTaxProcessor;
// AbstractFactory
// "интерфейс" фабрики
function FinancialToolsFactory() {
this.createShipFeeProcessor = function() {};
this.createTaxProcessor = function() {};
};
// Factories
// ConcreteFactory1
// Европейская фабрика будет возвращать нам экземпляры классов...
function EuropeFinancialToolsFactory() {
this.createShipFeeProcessor = function() {
// ...для расчета пошлины за перевозку для Европы
return new EuropeShipFeeProcessor();
};
this.createTaxProcessor = function() {
// ...для расчета налогов для Европы
return new EuropeTaxProcessor();
};
};
EuropeFinancialToolsFactory.prototype = new FinancialToolsFactory();
EuropeFinancialToolsFactory.prototype.constructor = EuropeFinancialToolsFactory;
// ConcreteFactory2
// аналогично, Канадская фабрика будет возвращать нам экземпляры классов...
function CanadaFinancialToolsFactory() {
this.createShipFeeProcessor = function() {
// ...для расчета пошлины за перевозку для Канады
return new CanadaShipFeeProcessor();
};
this.createTaxProcessor = function() {
// ...для расчета налогов для Канады
return new CanadaTaxProcessor();
};
};
CanadaFinancialToolsFactory.prototype = new FinancialToolsFactory();
CanadaFinancialToolsFactory.prototype.constructor = CanadaFinancialToolsFactory;
// Client
// класс для заказа товара
function OrderProcessor() {
var taxProcessor;
var shipFeeProcessor;
this.orderProcessor = function(factory) {
// метод создает экземпляры классов для:
shipFeeProcessor = factory.createShipFeeProcessor(); // расчета пошлин за перевозку
taxProcessor = factory.createTaxProcessor(); // расчета налогов
};
this.processOrder = function(order) {
// когда экземпляры классов для расчета созданы, нам надо только воспользоваться ими
// ...
var resShipFee = shipFeeProcessor.calculate(order);
var resTax = taxProcessor.calculate(order);
// ...
};
this.debug = function(str, order) {
// для наглядности
alert(str +": "+ shipFeeProcessor.calculate(order) +", "+ taxProcessor.calculate(order));
};
}
// использование
var eu = new OrderProcessor(); // создаем "пустой" класс для заказа товара
eu.orderProcessor(new EuropeFinancialToolsFactory()); // передаем ему новый экземпляр нужной нам фабрики
eu.processOrder(100); // производим заказ
eu.debug("eu", 100); // тест выведет: "eu: 111, 121"
var ca = new OrderProcessor();
ca.orderProcessor(new CanadaFinancialToolsFactory());
ca.processOrder(0);
ca.debug("ca", 0); // тест выведет: "ca: 12, 22"
Пример Delphi
program AbstractFactory;
{$APPTYPE CONSOLE}
uses
SysUtils;
type
// AbstractProduct
TCar = class(TObject)
public
function Info(): string; virtual; abstract;
end;
// ConcreteProductA
TFord = class(TCar)
public
function Info(): string; override;
end;
// ConcreteProductB
TToyota = class(TCar)
public
function Info(): string; override;
end;
// AbstractFactory
TCarFactory = class(TObject)
public
function CreateCar(): TCar; virtual; abstract;
end;
// ConcreteFactoryA
TFordFactory = class(TCarFactory)
public
function CreateCar(): TCar; override;
end;
// ConcreteFactoryB
TToyotaFactory = class(TCarFactory)
public
function CreateCar(): TCar; override;
end;
{ TFord }
function TFord.Info(): string;
begin
Result := 'Ford';
end;
{ TToyota }
function TToyota.Info(): string;
begin
Result := 'Toyota';
end;
{ TFordFactory }
function TFordFactory.CreateCar(): TCar;
begin
Result := TFord.Create();
end;
{ TToyotaFactory }
function TToyotaFactory.CreateCar(): TCar;
begin
Result := TToyota.Create();
end;
var
CF: TCarFactory;
C: TCar;
begin
WriteLn('Abstract factory');
WriteLn('ToyotaFactory');
CF := TToyotaFactory.Create();
C := CF.CreateCar();
WriteLn(C.Info());
C.Free();
CF.Free();
WriteLn('FordFactory');
CF := TFordFactory.Create();
C := CF.CreateCar();
WriteLn(C.Info());
C.Free();
CF.Free();
ReadLn;
end.
Пример Python
На практике в Python этот паттерн применяется редко.
#coding: utf-8
"""
Самолет
"""
class BaseVehicle(object):
def get_message(self):
raise NotImplementedError
class Airplane(object):
def __init__(self):
self.message = 'I am airplane'
def get_message(self):
return self.message
"""
Машина
"""
class Car(object):
def __init__(self):
self.message = 'I am car'
def get_message(self):
return self.message
"""
Фабрика средств передвижения
"""
class VehicleFactory(object):
objects = {
'car':Car,
'airplane':Airplane,
'default':Airplane
}
def get_vehicle(self, name='default'):
return self.objects.get(name, 'default')()
factory = VehicleFactory()
car = factory.get_vehicle('car')
airplane = factory.get_vehicle('airplane')
print car.get_message() #I am car
print airplane.get_message() #I am airplane
Пример PHP5
<?
interface GUIFactory {
public function createButton();
}
class WinFactory implements GUIFactory {
public function createButton() {
return(new WinButton());
}
}
class LinFactory implements GUIFactory {
public function createButton() {
return(new LinButton());
}
}
abstract class Button {
private $_caption;
public abstract function render();
public function getCaption(){
return $this->_caption;
}
public function setCaption($caption){
$this->_caption = $caption;
}
}
class WinButton extends Button {
public function render() {
echo "I am WinButton: ".$this->getCaption();
}
}
class LinButton extends Button {
public function render() {
echo "I am LinButton: ".$this->getCaption();
}
}
####
/**
* Класс инкапсулирует логику конструирования алгоритма создания каких либо структур
* например (GUI, алгоритмов доступа к БД, и т.д.). Класс ни чего "не знает" о платформе, на которой он работает.
*/
class Application {
public function __construct(GUIFactory $factory) {
$button = $factory->createButton();
$button->setCaption("Start");
$button->render();
}
}
/**
* Класс определяет платформу на которой работает и в соответствии от неё создаёт "класс-клиент", использующий "продукты"
* (в данном случае создание кнопок), с передаваемым параметром, определённой фабрики, в использование "клиентом".
*/
class ApplicationRunner {
public static function run() {
new Application(self::createOsSpecificFactory());
}
public static function createOsSpecificFactory() {
$sys = substr(PHP_OS, 0, 3);
if (strtoupper($sys) === 'WIN') {
return new WinFactory();
} else {
return new LinFactory();
}
}
}
ApplicationRunner::run();
Пример VB.NET
Class Program
Public Shared Sub Main()
'Абстрактная фабрика #1
Dim Factory1 As AbstractFactory = New ConcreteFactory1()
Dim C1 As New Client(Factory1)
C1.Run()
'Абстрактная фабрика #2
Dim Factory2 As AbstractFactory = New ConcreteFactory2()
Dim C2 As New Client(Factory2)
C2.Run()
'Ожидание пользователя
Console.Read()
End Sub
End Class
' "AbstractFactory"
MustInherit Class AbstractFactory
Public MustOverride Function CreateProductA() As AbstractProductA
Public MustOverride Function CreateProductB() As AbstractProductB
End Class
' "ConcreteFactory1"
Class ConcreteFactory1
Inherits AbstractFactory
Public Overrides Function CreateProductA() As AbstractProductA
Return New ProductA1()
End Function
Public Overrides Function CreateProductB() As AbstractProductB
Return New ProductB1()
End Function
End Class
' "ConcreteFactory2"
Class ConcreteFactory2
Inherits AbstractFactory
Public Overrides Function CreateProductA() As AbstractProductA
Return New ProductA2()
End Function
Public Overrides Function CreateProductB() As AbstractProductB
Return New ProductB2()
End Function
End Class
' "AbstractProductA"
MustInherit Class AbstractProductA
End Class
' "AbstractProductB"
MustInherit Class AbstractProductB
Public MustOverride Sub Interact(ByVal a As AbstractProductA)
End Class
' "ProductA1"
Class ProductA1
Inherits AbstractProductA
End Class
' "ProductB1"
Class ProductB1
Inherits AbstractProductB
Public Overrides Sub Interact(ByVal a As AbstractProductA)
Console.WriteLine(Me.[GetType]().Name & " взаимодействует с " & a.[GetType]().Name)
End Sub
End Class
' "ProductA2"
Class ProductA2
Inherits AbstractProductA
End Class
' "ProductB2"
Class ProductB2
Inherits AbstractProductB
Public Overrides Sub Interact(ByVal a As AbstractProductA)
Console.WriteLine(Me.[GetType]().Name & " взаимодействует с " & a.[GetType]().Name)
End Sub
End Class
'"Client" - Среда взаимодействия с продуктами
Class Client
Private abstractProductA As AbstractProductA
Private abstractProductB As AbstractProductB
'Конструктор
Public Sub New(ByVal factory As AbstractFactory)
abstractProductB = factory.CreateProductB()
abstractProductA = factory.CreateProductA()
End Sub
Public Sub Run()
abstractProductB.Interact(abstractProductA)
End Sub
End Class
Пример Ruby
class WinFactory
def create_button
WinButton.new
end
end
class LinFactory
def create_button
LinButton.new
end
end
class Button
attr_accessor :caption
end
class WinButton < Button
def render
puts "I`m WinButton #@caption"
end
end
class LinButton < Button
def render
puts "I`m LinButton #@caption"
end
end
class Application
def initialize(factory)
button = factory.create_button
button.caption = 'Start'
button.render
end
end
class ApplicationRunner
def self.run
Application.new(self.createOsSpecificFactory)
end
def self.createOsSpecificFactory
if RUBY_PLATFORM.downcase.include?("mswin")
WinFactory.new
else
LinFactory.new
end
end
end
ApplicationRunner.run
См. также
Это заготовка статьи по информатике. Помогите Википедии, дополнив её. |
Для улучшения этой статьи желательно:
|