Способ определения динамического декоратора в TS для длинного класса без переопределения всех методов - PullRequest
0 голосов
/ 16 января 2019

У меня есть класс с большим количеством методов.Давайте не будем здесь останавливаться на том, что, вероятно, этот класс может быть реорганизован и переписан как несколько классов, потому что это будет в конечном итоге, но не знаю.Я хотел бы иметь декоратор, который украшает только один метод этого класса.Мы можем сделать это несколькими способами.

Интерфейс класса:

interface IFoo {
    method1 (): number;
    method2 (a: string): number;
    method3 (b: IFoo): number;
    method4 (c: string | (() => string)): number;
    method5 (d: number, e: string): number;
}
  1. Классическое решение ООП: определить декоратор, который переопределяет определенные методы,и просто вызов супер реализации для всех остальных.Примерно так.

    class FooDecorator implements IFoo {
        constructor (
            private readonly provider: IFoo
        ) {}
    
        public method1 (): number {
            return this.provider.method1() + 1;
        }
    
        public method2 (a: string): number {
            return this.provider.method2.apply(this.provider, arguments);
        }
    
        public method3 (b: IFoo): number {
            return this.provider.method3.apply(this.provider, arguments);
        }
    
        public method4 (c: string | (() => string)): number {
            return this.provider.method4.apply(this.provider, arguments);
        }
    
        public method5 (d: number, e: string): number {
            return this.provider.method5.apply(this.provider, arguments);
        }
    }
    

    Как видите, довольно долгое написание и дублирование кода.

  2. Попробуйте использовать некоторые возможности JS.

    interface IFooDecorator {
        method1: IFoo["method1"];
    }
    
    class FooDecorator implements IFooDecorator {
        constructor (
            private readonly provider: IFoo
        ) {
            Object.setPrototypeOf(this, provider);
        }
    
        public method1 (): number {
            return this.provider.method1() + 1;
        }
    }
    

    Очевидными недостатками являются неправильная типизация и использование setPrototypeOf

Я также пытался использовать Proxy, но также слабая поддержка типизаций с использованием прокси.Есть ли другие решения для этого?Первый подход хорош, если мы можем автоматизировать переопределение методов без декорации с помощью вызова .apply.

1 Ответ

0 голосов
/ 16 января 2019

Реализуйте декоратор как фабричную функцию, которая использует Object.create вместо class синтаксиса, чтобы вам не приходилось использовать Object.setPrototypeOf:

function fooDecorator<T>(provider: IFoo): T implements IFoo {
    return Object.create(provider, {
        method1: {
            value(): number {
                return provider.method1() + 1;
            },
            writable: true,
            configurable: true
        }
    });
}
...