У заводской модели много применений. Я дам краткое описание их и их использования на очень простых примерах.
ПРИМЕЧАНИЕ. Примеры имеют только иллюстративное назначение, поэтому некоторые из них могут показаться излишними, а другие - не хорошим решением проблемы. Трудно дать реалистичный пример для всего, поэтому я дам себе некоторую свободу, игнорируя некоторые принципы в иллюстративных целях
Проблема: У вас есть класс, который имеет много конструкторов с разными параметрами. Это делает код трудным для чтения, записи и рассуждений.
Решение: Создайте фабрику, которая упрощает создание объектов и делает код чище благодаря наличию нескольких хорошо названных методов.
Пример: У вас есть система, которая имеет много различных типов продуктов.
public enum ProductType { Book, Paper, Pen }
public class Product {
public ProductType Type { get; set;}
}
public class ProductFactory {
public Product CreateBook() { return new Product(ProductType.Book); }
public Product CreatePaper() { return new Product(ProductType.Paper); }
public Product CreatePen() { return new Product(ProductType.Pen); }
}
Проблема: У вас есть объект, созданный из другого ввода и / или из-за необходимости обработки этого ввода. Или у вас есть объект, который имеет сложный творческий процесс.
Решение: Создайте фабрику, которая сделает это за вас с помощью хорошо названных методов.
Пример: У вас есть система, которая обрабатывает файлы из файловой системы и использует их расширения для сложных операций. Вы хотите использовать FileExtension class
для обработки равенства (в Windows регистр не учитывается) и других операций, чтобы избежать появления плавающих строк, избежать ошибок при сравнении без учета регистра и максимально использовать строгую типизацию
public class FileExtension { }
public class FileExtensionFactory {
public FileExtension Create(string extension) {
return new FileExtension(extension);
}
public FileExtension FromPath(string fullPath) {
return new FilePath(Path.GetExtension(fullPath);
}
}
public class SomeClassThatUsesTheFactory {
public void DoSomethingWithFileExtension(string filePath) {
var extension = FileExtensionFactory.FromPath(filePath);
// do something with the extension
}
}
Здесь вы можете видеть, что использование метода FromPath
делает код чище и более читабельным. Он также скрывает способ анализа параметра filePath
и позволяет избежать дублирования кода синтаксического анализа каждый раз, когда вам нужно создать расширение из filePath
.
.
Проблема: Вам необходимо создать экземпляры семейства связанных объектов, которые подключаются к вашей системе.
Решение: Использовать абстрактный шаблон фабричного дизайна.
Пример: Вы создаете ORM и хотите поддерживать различные типы баз данных. Вы хотите определить интерфейс для соединений с базой данных, который будет использовать ваш код ORM. Позже вы захотите настроить ORM с разными типами соединений, чтобы вы могли подключаться к разным базам данных. Вы хотите иметь возможность добавить поддержку большего количества баз данных в ваш ORM.
public interface IDbCommand : IDiposable {
string CommandText { get; set; }
void Execute();
}
public interface IDbConnection : IDisposable {
void Open();
void Close();
IDbCommand CreateCommand();
IDbTransaction BeginTransaction();
// other stuff
}
public interface IDbConnectionFactory {
IDbConnection CreateConnection();
}
public class MySqlCommand : IDbCommand { }
public class MySqlConnection : IDbConnection { }
public class MySqlConnectionFactory : IDbConnectionFactory { }
public class PostgreCommand : IDbCommand { }
public class PostgreConnection : IDbConnection { }
public class PostgreSqlConnectionFactory : IDbConnectionFactory { }
public class OrmSession {
public OrmSession(IDbConnectionFactory) { }
}
Здесь мы видим принцип Open-Closed в действии. Вы ORM будете использовать абстрактную фабрику, чтобы вы могли предоставить конкретную фабрику. Вы можете сделать это из своего кода, использовать файл конфигурации или использовать ServiceLocator или DI для внедрения конкретного завода.
Заметьте также кое-что интересное здесь. IDbConnection
также предоставляет CreateCommand
FactoryMethod . Каждое соединение должно создавать конкретную команду, поэтому он предоставляет метод для этого, даже если это не чисто фабрика.
Есть и другие ситуации, в которых вы можете использовать фабрики. Тестирование если один из них. Возможно, вам потребуется предоставить Abstract Factory, чтобы вы могли сделать тестируемые части вашего приложения.
В заключение, шаблон Factory имеет много применений. Они могут варьироваться от простого повышения чистоты и выразительности кода до достижения принципа Open-Closed. Движущей силой здесь является проблема, которая у вас есть. У вас проблемы с созданием объекта. Может ли фабрика решить вашу проблему?
Не всегда. Иногда создание объекта настолько сложно и имеет много разных вариаций, что Фабрика не помогает и может запутать вещи. Иногда вам нужен один или два конструктора.
В случае создания сложных возражений вы можете использовать BuilderPattern с или без FluentInterface .