Единственное, чего следует избегать, так это иметь слабые интерфейсы , подобные этому:
interface DataProviderSource {
dataURL?: string;
dataArchive?: ArrayBuffer;
}
, поскольку, поскольку каждое свойство является необязательным, оно позволяет передавать пустой объект.Мы не хотим этого - мы хотим, чтобы передавался ровно один формат данных.
Это вопрос вкуса.Один из возможных вариантов:
class Processor {
static fromArrayBuffer(source: ArrayBuffer) {}
static fromString(source: string) {}
process(source: string | ArrayBuffer) {
if (source instanceof ArrayBuffer) {
return Processor.fromArrayBuffer(source);
}
return Processor.fromString(source);
}
}
Это просто, но нарушает принцип открытия / закрытия.Вы также можете моделировать свои источники с помощью именованных конструкторов.В этой конструкции каждый тип источника оснащен собственным процессором.
interface Source<T = any> {
data: T;
process: () => void;
}
class DataURL implements Source<string> {
constructor(readonly data: string) {
this.data = data;
};
process() {}
}
class Archieve implements Source<ArrayBuffer> {
constructor(readonly data: ArrayBuffer) {
this.data = data;
};
process() {}
}
class SomeOther implements Source<string> {
constructor(readonly data: string) {
this.data = data;
};
process() {}
}
Это решение открыто для расширения.Единственное, что имеет значение для источника, это реализовать интерфейс Source
.
const process = (...sources: Source[]): void =>
sources.forEach(source => source.process())
process(
new DataURL('hello'),
new Archieve(new ArrayBuffer(32)),
new SomeOther('world')
);