user_of_toster
@user_of_toster

Как сделать фабрику?

Пусть у нас есть абстракный Figure:
interface FigureData {
  width: number,
}

abstract class Figure<T extends FigureData> {
  constructor(data: T) {};
}

Triangle:
interface TriangleData extends FigureData {
  someTriangleProperty: string,
}

class Triangle extends Figure<TriangleData>{
  constructor(data: TriangleData) {
    super(data);
  }
}

Circle:
interface CircleData extends FigureData {
  radius: number,
}

class Circle extends Figure<CircleData> {
  constructor(data: CircleData) {super(data)};
}

Теперь я хочу, чтобы репозиторий получал на входе ID фигуры и возвращал инстанс фигуры. Для этого мне нужна фабрика:
class FigureFactory<T extends FigureData> {
  create(type: string, data: T) {
    if (type == 'CIRCLE') return new Circle(data)
    else if (type === 'TRIANGLE') return new Triangle(data);
  }
}

Однако компилятор не дает этого сделать:
Argument of type 'T' is not assignable to parameter of type 'CircleData'.
Property 'radius' is missing in type 'FigureData' but required in type 'CircleData'.ts(2345)

Вопрос #1 - как угомонить компилятор?
Вопрос #2 - пишу ли я говнокод и если да, то как сделать лучше?
  • Вопрос задан
  • 325 просмотров
Решения вопроса 2
sarapinit
@sarapinit
Точу водой камень
Вы на самом деле не гарантируете что тип переданный в Circle будет CircleData.
В typescript структурная типизация. Вам либо надо убедиться что структура входных данных соответствует CircleData либо ввести в FigureData поле type которое вы будете фиксировать в каждом наследнике.

И да, у вас плохой код, потому что ваше наследование нарушает принцип подстановки Лисков. Причем вы взяли классический пример, на котором обычно и демонстрируют нарушение этого принципа.
Ответ написан
profesor08
@profesor08
как угомонить компилятор?

Не надо это делать. Он все правильно показывает.

пишу ли я говнокод и если да, то как сделать лучше?

Станет проще и легче пользоваться кодом? Нет - значит да, да - нет.

Как добавить в твою фабрику создание звезды? Надо переписать метод, который проверит, что ты хочешь и создаст звезду. Но тогда зачем все это полотно кода? Не проще ли ограничиться одной функцией и не морочить себе голову наследованием? Либо создавать их по месту не переписываю код.

А если взять и унаследоваться от фабрики и расширить ее своим методом для создания звезды? Написанный код не изменится, реализации не поменяются, и вообще это оказывается быстро и просто. Но тогда не плохо бы и начальный класс реализовать в таком ключе, чтоб для каждого нужного объекта, был бы свой метод, который гарантировано вернет нужный объект. И вдруг окажется, что и паттерн работает, и наследование работает, и проще как-то стало.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы