Реализовать абстрактную фабрику, создающую типизированные экземпляры
Реализуйте порождающий паттерн GoF abstract factory (абстрактная фабрика). Опишите базовый VehicleFactory, чей метод create(type) бросает исключение (он абстрактный). Опишите конкретный CarFactory extends VehicleFactory, чей create(type) возвращает экземпляр Sedan или Coupe (оба — подклассы базового Car, хранящего this.type), и бросает Error('Unknown car type') для всего остального.
Требование: вызывающий код зависит только от интерфейса фабрики, но не от конкретных конструкторов продуктов.
class VehicleFactory {
create(type) {
// ваш код здесь
}
}
Допишите реализацию.
Базовый create бросает исключение, чтобы абстрактный класс нельзя было использовать напрямую. В CarFactory.create через switch по type вернуть new Sedan() или new Coupe(), иначе бросить ошибку. Вызывающий код держит ссылку на VehicleFactory и зовёт create, поэтому подмена другого подкласса фабрики меняет семейство продуктов без правок этого кода.
- ✗Позволять базовому
createчто-то возвращать вместо исключения, из-за чего абстрактную фабрику можно вызвать напрямую - ✗Возвращать обычные литералы объектов вместо настоящих экземпляров
Sedan/Coupe, теряя цепочку прототипов иinstanceof - ✗Забывать ветку
default/else, из-за чего неизвестный тип молча возвращаетundefinedвместо исключения
- →Как зависимость от
VehicleFactory, а не отnew Sedan(), упрощает расширение вызывающего кода? - →Как добавить второе семейство продуктов, скажем
TruckFactory, не меняя существующих вызовов?
Решение
Базовый класс делает метод абстрактным через throw, конкретная фабрика ветвится по типу.
class Car {
constructor(type) {
this.type = type;
}
}
class Sedan extends Car {
constructor() {
super('Sedan');
}
}
class Coupe extends Car {
constructor() {
super('Coupe');
}
}
class VehicleFactory {
create(type) {
throw new Error('create() must be implemented by a subclass');
}
}
class CarFactory extends VehicleFactory {
create(type) {
switch (type) {
case 'Sedan':
return new Sedan();
case 'Coupe':
return new Coupe();
default:
throw new Error('Unknown car type');
}
}
}
const factory = new CarFactory();
const car = factory.create('Sedan'); // Car { type: 'Sedan' }
Как это работает
VehicleFactory задаёт интерфейс: метод create, который базовый класс лишь объявляет и сразу бросает исключение. Это превращает его в абстрактный — прямое использование невозможно, и нужно наследоваться.
CarFactory реализует create, выбирая конкретный класс продукта по type. Возвращаются настоящие экземпляры Sedan/Coupe, поэтому работает instanceof Car и сохраняется цепочка прототипов. Неизвестный тип попадает в default и приводит к понятной ошибке.
Главная выгода: вызывающий код держит ссылку типа VehicleFactory и зовёт create. Подставив TruckFactory, мы меняем целое семейство продуктов, не трогая код, который их потребляет.