简体   繁体   中英

Multiple Object wrappers in TypeScript/JavaScript

I have an interface MyInterface and a concrete implementation MyImplementation that implements the interface. Now I need to create multiple "Wrappers" that should also implement MyInterface and will be wrapping the original MyImplementation object. Wrapping in a sense that properties and function methods on the wrapper will serve as a kind of Proxy - ie performing some checks on the input data and pass it down to the original implementation of MyImplementation . I need to stack the multiple wrappers into each others, ie have an MyValidator1 , MyValidator2 etc. that can be - depending on the use case - all added to a single object.

Some code to make things clearer:

interface MyInterface {
    method1(arg1, arg2): any;
}

class MyImplementation implements MyInterface {
    method1(arg1, arg2) {
        /* perform checks and or throw */
    }
}

class MyValidator1 implements MyInterface {
    method1(arg1, arg2) {
        /* ... */
    }
}

class MyValidator2 implements MyInterface {
    method1(arg1, arg2) {
        /* ... */
    }
}

let o1 = new MyImplementation();
// only apply validator1
AddValidator1(o1);

let o2 = new MyImplementation();
// only apply validator2
AddValidator2(o2);

let o3 = new MyImplementation();
// apply both validators
AddValidator1(o3);
AddValidator2(o3);

// intended call hierarchicy when calling o3.method1(arg1, arg2)
// MyValidator1.method1(arg1, arg2)
// MyValidator2.method1(arg1, arg2)
// MyImplemenation.method1(arg1, arg2)
// but the order of the validators is not important!

This is just some code suggestion, I am looking for all kinds of patterns that might differ from the above code to achieve this.

It is important that all instances of MyInterface implemenations are encapsulated - they should behave as if they were MyImplemenation to a consumer. The Validators should possibly add private functions or properties.

Whats the best way to do this? Maybe changing the prototype at runtime?

I don't know TypeScript, but here how it would be done in regular Javascript (ES6 syntax):

class MyInterface {
  foo() {
    throw new Error('To be implemented');
  }
}

class MyImplementation extends MyInterface {
  foo() {
    return 42;
  }
}

function wrapWithValidator1(impl) {
  class MyValidator1 extends MyInterface {
    constructor() {
      for (const key of Object.keys(impl)) {
        this[key] = impl[key];
      }
    }

    foo() {
      validateStuff();
      return impl.foo();
    }
  }

  return new MyValidator1();
}

function wrapWithValidator2(impl) {
  class MyValidator2 extends MyInterface {
    constructor() {
      for (const key of Object.keys(impl)) {
        this[key] = impl[key];
      }
    }

    foo() {
      validateOtherStuff();
      return impl.foo();
    }
  }

  return new MyValidator2();
}

Your validators are wrappers over the implementation because they "extend" it. They inherit from the implementation prototype (and thus all its properties/methods), but they can override an existing method to provide additional behavior.

Use super.myMethod() when you override a method to call the parent method.

How about having a list of validators in the MyImplementation class?
Something like:

abstract class Validator implements MyInterface {
    abstract method1(arg1, arg2): any;
}

class MyValidator1 extends Validator {
    method1(arg1, arg2) {
        /* ... */
    }
}

class MyValidator2 extends Validator {
    method1(arg1, arg2) {
        /* ... */
    }
}

class MyImplementation implements MyInterface {
    private validators: Validator[];

    constructor() {
        this.validators = [];
    }

    addValidator(validator: Validator) {
        this.validators.push(validator);
    }

    method1(arg1, arg2) {
        this.validators.every(validator => { /* do something here */ return false; });
        /* perform checks and or throw */
    }
}

( code in playground )

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM