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 */
}
}
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.