Ответ
Для создания объектов, тип которых зависит от контекста или входных параметров, я обычно применяю Фабричный метод (Factory Method) или Абстрактную фабрику (Abstract Factory).
Фабричный метод отлично подходит, когда логика создания инкапсулирована в подклассах. Абстрактная фабрика — когда нужно создавать семейства связанных объектов.
На практике, для простого контекстного создания, я часто использую простую фабрику (Simple Factory). Вот пример на C#, где в зависимости от типа формата создается соответствующий логгер:
public interface ILogger
{
void Log(string message);
}
public class FileLogger : ILogger
{
public void Log(string message)
{
File.AppendAllText("app.log", message);
}
}
public class ConsoleLogger : ILogger
{
public void Log(string message)
{
Console.WriteLine($"LOG: {message}");
}
}
public static class LoggerFactory
{
public static ILogger CreateLogger(string loggerType)
{
return loggerType.ToLower() switch
{
"file" => new FileLogger(),
"console" => new ConsoleLogger(),
_ => throw new ArgumentException("Unsupported logger type"),
};
}
}
// Использование
ILogger logger = LoggerFactory.CreateLogger("file");
logger.Log("Application started.");
Этот подход отделяет код, использующий логгер, от конкретных классов логгеров, упрощая расширение и тестирование.
Ответ 18+ 🔞
А, ну это же классика, ёпта! Сидишь такой, пишешь код, и тут бац — нужно объекты создавать, а какой именно нужен, заранее нихуя не ясно. Типа, смотри, пользователь в конфиге написал «file» или «console», а ты должен как волшебник из шляпы вытащить правильную реализацию. Пиздец как знакомо.
Вот в таких случаях все умные дядьки в книжках советуют Фабричный метод или Абстрактную фабрику. Первый — это когда ты делегируешь создание объектам-наследникам, типа «ребята, сами решайте, как вас порождать». Второй — когда у тебя целая банда связанных объектов, и их всех нужно создавать согласованно, чтобы, не дай бог, WindowsButton не встал в паре с MacOSCheckbox. Абстрактная фабрика — это уже для серьёзных пацанов, когда архитектура разрослась до овердохуища.
Но честно? Чаще всего хватает простой, блядь, фабрики — не мудрим, просто статический метод, который по какому-то условию возвращает нужный объект. Работает, и мозг не ебёт.
Смотри, вот тебе живой пример на C#. Допустим, нам нужны логгеры. Интерфейс один, а реализаций — несколько.
public interface ILogger
{
void Log(string message);
}
public class FileLogger : ILogger
{
public void Log(string message)
{
File.AppendAllText("app.log", message);
}
}
public class ConsoleLogger : ILogger
{
public void Log(string message)
{
Console.WriteLine($"LOG: {message}");
}
}
Всё просто, да? Один пишет в файл, другой — в консоль. А теперь самое интересное — фабрика, которая их рожает.
public static class LoggerFactory
{
public static ILogger CreateLogger(string loggerType)
{
return loggerType.ToLower() switch
{
"file" => new FileLogger(),
"console" => new ConsoleLogger(),
_ => throw new ArgumentException("Unsupported logger type"),
};
}
}
Видишь эту красоту? switch выражение, всё чётко. Сказали «file» — получи FileLogger. Сказали «console» — на тебе ConsoleLogger. А если какую-то хуйню написали — получите исключение прямо в ебало, разбирайтесь.
Использовать — вообще элементарно, ядрёна вошь:
ILogger logger = LoggerFactory.CreateLogger("file");
logger.Log("Application started.");
И весь твой основной код теперь нихуя не знает про конкретные классы логгеров. Он работает с интерфейсом ILogger. Захотел поменять логику создания или добавить новый тип логгера (например, NetworkLogger) — идёшь в фабрику, дописываешь одну строку в switch, и ни одна другая часть кода даже не чихнёт. Волнение ебать, как удобно!
Вот и вся магия. Никаких сложных паттернов, если не надо. Простая фабрика — и уже жить становится проще, а код чище. Главное — не превращать эту фабрику в божественный объект, который знает всё на свете, а то будет пизда рулю.