With OOP what is the recommended way to pass an instance of a class which is restricted - such as read-only properties or less methods available.
Below is a Vector2
, which contains multiple methods for manipulating it's properties such as the setters or the add
function.
class Vector2 {
private _x: number = 0;
private _y: number = 0;
public get x () {
return this._x;
}
public get y () {...}
public set x (x: number) {
this._x = x;
}
public set y (y: number) {...}
public add (v: Vector2) {
this._x += v.x;
this._y += v.y;
}
}
How would I pass a restricted version of this instance, for example a read-only Vector2
with only the getters available. The solution I've had is to create another seperate class I'll name Vector2RO
which wraps around a Vector2
but I feel like there could be a "better" or more "elegant" way to do so.
class Vector2RO {
private _v: Vector2;
public constructor (v: Vector2) {
this._v = v;
}
public get x () {
return this._v.x;
}
}
-
2You could define an interface Vector2RO, and have Vector2 implement that interface, extending it with mutators. Then, you can reasonably pass around the Vector2RO object.BobDalgleish– BobDalgleish2018年03月15日 21:40:39 +00:00Commented Mar 15, 2018 at 21:40
-
1Nothing significantly more elegant. You have several options. You either (1) wrap the object like that (but then you have to be careful that something doesn't change the wrapped instance unintentionally), (2) return a copy of the vector to a client that requests it, and then it's their business (works well if copying the object is cheap), or (3) work exclusively with immutable objects (once you construct it, it cannot be changed; if you want different coordinates, you have to create another instance; again, works well if constructing the objects is cheap).Filip Milovanović– Filip Milovanović2018年03月15日 21:40:42 +00:00Commented Mar 15, 2018 at 21:40
-
P.S. BTW, implementing a read-only interface is similar to my case (1) in the comment above (works, but have to be careful, as client code can cast the object to its actual type). It is a less work then writing a wrapper, though.Filip Milovanović– Filip Milovanović2018年03月15日 21:45:07 +00:00Commented Mar 15, 2018 at 21:45
-
1@FilipMilovanović the integration segregation principle would have you create an interface narrowed down to what the client actually uses anyway. Whether that's enough depends on how hostile you consider the other coders.candied_orange– candied_orange2018年03月16日 01:43:58 +00:00Commented Mar 16, 2018 at 1:43
-
@FilipMilovanović - Copying the object is not an option in my case, I've ended up creating a wrapper class.Alex– Alex2018年03月16日 08:24:04 +00:00Commented Mar 16, 2018 at 8:24
1 Answer 1
In C++, I'd just use a const
reference. In languages without such type qualifiers, a decorator or wrapper like you suggested is the standard approach. I know of similar examples in Python or Java.
It's important to spend some thought on the relation between a readonly wrapper and the mutable object. Should they share an interface? The fact is that the mutable object will also implement all the methods that are part of the readonly interface. So it might make sense to have Vector2
implement the Vector2ReadOnly
inteface. On the other hand, the Vector2
is not read-only, and implementing such an interface would be highly misleading.
My recommendation would be to avoid inheritance, and instead use a completely independent class for the read-only wrapper. Alternatively, the interface should make it clear that the object is not immutable, but that this interface merely contains the getters or the read-only part of the interface. Vector2Getters
might be an accurate though rather awkward name.
-
Avoiding inheritance with an independant class is what I've ended up doing.Alex– Alex2018年03月16日 08:22:44 +00:00Commented Mar 16, 2018 at 8:22