Библиотека для работы с геометрическими фигурами (прямоугольник, треугольник, круг), написанная на TypeScript. Предоставляет единый API для создания фигур, расчёта площади и периметра, а также возможность расширения новыми типами фигур.
- Web API стандарты: Наследование от
EventTargetи расширение классаEvent. - Принцип DRY: Вся логика асинхронного кэширования и генерации событий инкапсулирована в базовом классе
Shape. Конкретные фигуры описывают только чистую математику. - Принцип Open/Closed (SOLID): Фабрика не имеет жестких ветвлений
if/else. Любая новая фигура регистрируется извне и инстанцируется через статический метод десериализации. - Иммутабельность: Свойства фигур доступны только для чтения (
readonly). Для изменения параметров используется методclone.
import { ShapeFactory, Rectangle, Circle, Triangle } from 'geometry-library';
// 1. Создаём фабрику
const factory = new ShapeFactory();
// 2. Регистрируем нужные фигуры вручную
factory.register('rectangle', Rectangle);
factory.register('circle', Circle);
factory.register('triangle', Triangle);
// 3. Асинхронное создание
const rect = await factory.create<Rectangle>('rectangle', 5, 10);
const circ = await factory.create<Circle>('circle', 7);
const tri = await factory.create<Triangle>('triangle', 3, 4, 5);
// Расчёт площади и периметра
console.log(await rect.getArea()); // 50
console.log(await rect.getPerimeter()); // 30Фабрика регистрирует типы фигур и создаёт их асинхронно:
const factory = new ShapeFactory();
factory.register('square', Square); // ваш класс Square
const square = await factory.create('square', 10);При создании фабрика генерирует событие shapecreated, на которое можно подписаться (ДО вызова создания):
factory.addEventListener('shapecreated', (e) => {
console.log('Создана фигура:', e.shape.getParameters());
});Каждая фигура возвращает свои параметры через метод getParameters(), что удобно для сериализации:
const par = rect.getParameters();
// { type: 'rectangle', width: 5, height: 10 }По этим параметрам можно восстановить фигуру:
const restored = await factory.createFromParameters(par);Методы getArea() и getPerimeter() возвращают Promise<number>. При первом вызове результат кэшируется и генерирует события areacalculated / perimetercalculated:
rect.addEventListener('areacalculated', (e) => {
console.log(`Площадь: ${e.area}`);
});
const area = await rect.getArea();Метод clone() позволяет создать копию фигуры с изменёнными параметрами:
const newRect = rect.clone({ width: 15 }); // высота останется 10Чтобы добавить новую фигуру, необходимо:
- Унаследовать абстрактный класс
Shape<T>. - Реализовать геттеры
type,area,perimeter, методgetParameters(), статический методfromParameters()и методclone(). - Зарегистрировать класс в фабрике.
Пример (квадрат):
import { Shape, ShapeConstructor } from 'geometry-library';
interface SquareParameters extends ShapeParameters {
type: 'square';
side: number;
}
class Square extends Shape<SquareParameters> {
readonly type = 'square' as const;
constructor(public readonly side: number) {
super();
if (side <= 0) throw new InvalidShapeArgumentError('Side must be positive');
}
get area() { return this.side ** 2; }
get perimeter() { return this.side * 4; }
getParameters(): SquareParameters {
return { type: 'square', side: this.side };
}
static fromParameters(params: SquareParameters): Square {
return new Square(params.side);
}
clone(changes: Partial<SquareParameters> = {}): Square {
return new Square(changes.side ?? this.side);
}
}
// Регистрируем
factory.register('square', Square);Библиотека экспортирует ряд ошибок:
InvalidShapeArgumentError— некорректные аргументы конструктора.UnknownShapeTypeError— попытка создать незарегистрированный тип.ShapeAlreadyRegisteredError— попытка зарегистрировать уже существующий тип.
Все ошибки наследуют стандартный Error.
Код использует глобальные типы Event и EventTarget. Для компиляции TypeScript необходимо добавить "DOM" в lib вашего tsconfig.json:
{
"compilerOptions": {
"target": "ES2020",
"lib": ["ES2020", "DOM"],
"strict": true,
"allowJs": false
}
}Если вы работаете в среде, где Event и EventTarget недоступны (например, Node.js < 15 без полного DOM), рекомендуется либо обновить Node.js, либо предоставить полифилл.
- создание и валидацию всех трёх фигур;
- вычисление площади и периметра;
- сериализацию / десериализацию (getParameters / fromParameters);
- клонирование с частичным изменением;
- кэширование расчётов и генерацию событий (getArea / getPerimeter);
- фабрику: регистрацию, дубликаты, создание, события;
- кастомные типы фигур;
- ошибки.