#typescript #class #oop
#typescript #класс #ооп
Вопрос:
Я изо всех сил пытаюсь создать родительский класс для этого типа «нормализатора». У меня есть пара классов, которые используют одну и ту же структуру классов. Я бы хотел, чтобы способ EmailNormalizer
просто содержал часть логики внутри конструктора и имел все общие функциональные возможности, спрятанные в родительском классе.
У меня есть этот класс нормализатора электронной почты:
export class EmailNormalizer {
readonly TYPE: string | EmailNormalizer;
normalized: string;
constructor(raw: EmailNormalizer['TYPE']) {
if (!raw) throw new Error('Invalid Email');
if (raw instanceof EmailNormalizer) {
this.normalized = raw.normalized;
} else {
const results = email.analyze(raw);
if (results) throw new Error(`Email ${results.error}`);
this.normalized = _normalizeEmail(raw);
}
}
static normalize(raw: EmailNormalizer['TYPE']) {
return new EmailNormalizer(raw).normalized;
}
}
Вы можете использовать его двумя способами
new EmailNormalizer('hello@boom.com').normalize
EmailNormalizer.normalize('hello@boom.com')
Я пытаюсь создать общий родительский класс «нормализатора», чтобы не забыть ни одну из частей.
Это была моя первая попытка. У меня возникли проблемы со статическим методом, а затем я столкнулся с проблемами, когда попытался создать более общий метод нормализатора.
class Normalizer<In = unknown, Out = unknown> {
readonly TYPE: In;
normalized: Out;
normalize: (raw: In) => Out;
constructor(raw: In) {
this.normalized = this.normalize(raw);
}
static normalize<In, T extends typeof Normalizer>(this: T, raw: In) {
return new this(raw).normalized;
}
}
export class EmailNormalizer extends Normalizer<EmailNormalizer | string, string> {
normalize = (raw: Email['TYPE']) => {
if (raw instanceof Email) return raw.normalized;
if (!raw) throw new Error('Invalid Email');
const results = email.analyze(raw);
if (results) throw new Error(`Email ${results.error}`);
return _normalizeEmail(raw);
};
}
function normalize<I extends any, O extends any, T extends Normalizer<I, O>>(i: T, value) {
return new i(value).normalized;
}
// ideally
EmailNormalizer.normalize('HELLO@gmail.com');
// or
normalize(EmailNormalizer, 'HELLO@gmail.com')
Кто-нибудь может помочь разработать родительский класс normalize?
Должен ли этот родительский класс быть абстрактным?
Комментарии:
1. Пара вопросов: 1) вы уверены, что выполнение логики нормализации внутри конструктора в порядке? 2) вы уверены, что желание использовать общий статический метод является веской причиной для создания (потенциально) абстрактного базового класса и вообще использования наследования? 3) рассматривали ли вы возможность использования композиции вместо наследования?
Ответ №1:
Я мог бы предложить рассмотреть возможность использования композиции вместо наследования. Например, здесь был бы полезен некоторый шаблон стратегии:
interface NormalizerStrategy<In, Out> {
normalize: (raw: In) => Out;
}
class EmailNormalizerStrategy implements NormalizerStrategy<string, string> {
normalize(raw: string): string {
// pretend like there is some processing here
const result = raw;
return resu<
}
}
class AgeNormalizerStrategy implements NormalizerStrategy<string, number> {
normalize(raw: string): number {
// pretend like there is some processing here
const result = Number(raw);
return resu<
}
}
class Normalizer<In, Out> {
constructor(private readonly strategy: NormalizerStrategy<In, Out>) {}
normalize(input: In): Out {
this.someProcessingCommonToAllTheStrategies(input);
return this.strategy.normalize(input);
}
private someProcessingCommonToAllTheStrategies(data: In): void {
// pretend like there is some processing here
}
}
const emailNormalizer = new Normalizer(new EmailNormalizerStrategy);
const normalizedEmail: string = emailNormalizer.normalize('some email');
const ageNormalizer = new Normalizer(new AgeNormalizerStrategy);
const normalizedAge: number = ageNormalizer.normalize('some age');