Данный шаблон
предоставляет интерфейс
для создания семейств взаимосвязанных
или взаимозависимых объектов, без
указания их конкретных классов.
Паттерн
«Абстрактная фабрика», как и паттерн
«Фабричный метод» используется для
создания объектов. Но их основное
различие в том, что он разрешает создание
объектов классов, связанных между собой.
Где на диаграмме:
- AbstractFactory - абстрактная фабрика:- объявляет интерфейс для операций, создающих абстрактные объекты-продукты;
- ConcreteFactory - конкретная фабрика:- реализует операции, создающие конкретные объекты-продукты;
- AbstractProduct - абстрактный продукт:- объявляет интерфейс для типа объекта-продукта;
- ConcreteProduct - конкретный продукт:- определяет объект-продукт, создаваемый соответствующей конкретной фабрикой;- реализует интерфейс Abstract Product;
- Client - клиент:- пользуется исключительно интерфейсами, которые объявлены в классах AbstractFactory и AbstractProduct.
Реализация
Для примера
рассмотрим библиотеку, которая будет
содержать в себе классы для работы с
разными СУБД. Проектировщик библиотеки
возможно захочет держать ее классы
слабо связанными с клиентскими
приложениями. Таким образом новые классы
для работы с СУБД можно будет легко
встроить в приложения.
Давайте
предположим, что для работы с СУБД нам
необходимо два класса — Connection и Command.
Это могут быть абстрактные классы, с
реализациями для каждого типа СУБД. К
примеру, для mySql это может быть MySqlCommand
и MySqlConnection. По такому же принципу, для
Oracle это будут OracleCommand и OracleConnection.
Клиентское
приложение не использует библиотеки
СУБД напрямую (чтобы сохранить принцип
слабого связывания). Вместо этого
используются абстрактные классы. Для
этого потребуется:
- Механизм, который позволит получать экземпляры классов для необходимых СУБД
- Гарантировать, что классы могут использоваться СУБД только одного типа в единицу времени.
Это может быть
сделано путем создания иерархии фабрик.
Каждая фабрика будет иметь фабричный
метод который создаст экземпляр класса
для СУБД. Это ограничит создание объектов
только для определенной СУБД в единицу
времени.
Давайте посмотрим, как это будет выглядеть на Java.
Command.java
package ua.dp.allmycircuits.abstractfactory;
/**
* Абстрактный класс для SQL команд
* @author winkiller
*/
public abstract class Command {
public abstract ResultSet execute();
}
Connection.java
package ua.dp.allmycircuits.abstractfactory;
/**
* Абстрактный класс для соединения с СУБД
* @author winkiller
*/
public abstract class Connection {
public abstract void connect();
}
MySqlCommand.java
package ua.dp.allmycircuits.abstractfactory;
/**
* Реализация Command для mySQL
* @author winkiller
*/
public class MySqlCommand extends Command{
@Override
public ResultSet execute() {
System.out.println("MySqlCommand.execute");
return new MySqlResultSet();
}
}
OracleCommand.java
package ua.dp.allmycircuits.abstractfactory;
/**
* Реализация Command для Oracle
* @author winkiller
*/
public class OracleCommand extends Command{
@Override
public ResultSet execute() {
System.out.println("OracleCommand.execute");
return new OracleResultSet();
}
}
MySqlConnection.java
package ua.dp.allmycircuits.abstractfactory;
/**
* Реализация класса для соединения с mySQL
* @author winkiller
*/
public class MySqlConnection extends Connection{
@Override
public void connect() {
System.out.println("MySqlConnection.connect");
}
}
OracleConnection.java
package ua.dp.allmycircuits.abstractfactory;
/**
* Реализация класса для соединения с Oracle
* @author winkiller
*/
public class OracleConnection extends Connection{
@Override
public void connect() {
System.out.println("OracleConnection.connect");
}
}
DbFactory.java
package ua.dp.allmycircuits.abstractfactory;
/**
* Абстрактный класс фабрики
* @author winkiller
*/
public abstract class DbFactory {
public abstract Connection createConnection();
public abstract Command createCommand();
}
MySqlFactory.java
package ua.dp.allmycircuits.abstractfactory;
/**
* Реализация фабрики для mySQL
* @author winkiller
*/
public class MySqlFactory extends DbFactory{
@Override
public Connection createConnection() {
return new MySqlConnection();
}
@Override
public Command createCommand() {
return new MySqlCommand();
}
}
OracleFactory.java
package ua.dp.allmycircuits.abstractfactory;
/**
* Реализация фабрики для Oracle
* @author winkiller
*/
public class OracleFactory extends DbFactory{
@Override
public Connection createConnection() {
return new OracleConnection();
}
@Override
public Command createCommand() {
return new OracleCommand();
}
}
ResultSet.java
package ua.dp.allmycircuits.abstractfactory;
/**
* Абстрактный класс для результата
* @author winkiller
*/
public abstract class ResultSet {
public abstract void hasNext();
}
MySqlResultSet.java
package ua.dp.allmycircuits.abstractfactory;
/**
* Реализация класса для результата mySQL
* @author winkiller
*/
public class MySqlResultSet extends ResultSet{
@Override
public void hasNext() {
System.out.println("MySqlResultSet.hasNext");
}
}
OracleResultSet.java
package ua.dp.allmycircuits.abstractfactory;
/**
* Реализация класса для результата Oracle
* @author winkiller
*/
public class OracleResultSet extends ResultSet{
@Override
public void hasNext() {
System.out.println("OracleResultSet.hasNext");
}
}
AbstractFactory.java
package ua.dp.allmycircuits.abstractfactory;
/**
* Проверка абстрактной фабрики
* @author winkiller
*/
public class AbstractFactory {
public static void main(String[] args) {
transact(new MySqlFactory());
transact(new OracleFactory());
}
private static void transact(DbFactory db){
Connection con = db.createConnection();
con.connect();
Command cmd = db.createCommand();
ResultSet set = cmd.execute();
set.hasNext();
}
}
Плюсы
- Позволяет придерживаться принципа слабого связывания
- Ограничивает использование классов из одного семейства/конфигурации в одну единицу времени
- Легкое изменение конфигурации
Минусы
- Количество классов, которое может быть проинициализировано, ограничено интерфейсом абстрактной фабрики
- Не совсем удобное добавление новых классов
Исходники примера можно скачать с Github
Комментариев нет:
Отправить комментарий