I have a class that manages a WebSocket connection and provides the methods to subscribe to this WebSocket. An instance of this class may be passed to many child objects that subscribe to this WebSocket via these methods:
const client = new WebSocketManager();
await client.connect();
const objA = new ClassA(client);
const objB = new ClassB(client);
client.close(); // at a future point in time
The problem is that client
exposes critical methods like connect
and close
. If objA calls close
, objB would fail for no apparent reason. Those two methods should be private to the children, but public to the initiator of the parent object. Is there a pattern to solve this problem? Two methods are presented below. Are any of those two patterns acceptable or are there better solutions? I would like to hear your opinion.
Method 1: Define an owner of the parent object. Restricted methods require a reference to the owner.
class Parent {
#owner;
constructor(owner) {
this.#owner = owner;
}
restricedMethod(owner) {
if(owner !== this.#owner)
throw Error('not authorized');
console.log('restricedMethod called');
}
accessibleMethod() {
console.log('accessibleMethod called');
}
}
class Child {
constructor(dependency) {
this.dependency = dependency;
}
callAccessibleMethod() {
this.dependency.accessibleMethod();
}
callRestricedMethod() {
this.dependency.restricedMethod();
}
}
const parent = new Parent(this);
// 'this' is the owner of 'parent'
const child = new Child(parent);
child.callAccessibleMethod();
// accessibleMethod called
try { child.callRestricedMethod(); } catch(e) { console.log(e.message); }
// Error: not autherized
parent.restricedMethod(this); // only the owner can call this method
// restricedMethod called
Method 2: Create a new parent object on the fly that only contains the methods that the child may access.
class Parent {
restricedMethod(){
console.log('restricedMethod called');
}
accessibleMethod(){
console.log('accessibleMethod called');
}
}
class Child {
constructor(dependency) {
this.dependency = dependency;
}
callAccessibleMethod() {
this.dependency.accessibleMethod();
}
callRestricedMethod() {
this.dependency.restricedMethod();
}
}
class MethodSelection {
constructor(object, methods) {
for (const method of methods)
this[method] = object[method];
}
}
const parent = new Parent();
// select methods from parent object and create new object
const restricted = new MethodSelection(parent, ['accessibleMethod']);
console.log(restricted.accessibleMethod === parent.accessibleMethod);
// true
const child = new Child(restricted);
child.callAccessibleMethod();
// accessibleMethod called
try { child.callRestricedMethod(); } catch(e) { console.log(e.message); }
// TypeError: this.dependency.restricedMethod is not a function
parent.restricedMethod();
// restricedMethod called
Aucun commentaire:
Enregistrer un commentaire