After adopting Prototype Pattern into a game, it pleasantly improved maintainability of my code.
However, I have started to fear that when the actual object become more detail-customized,
I tend to code the corresponding prototype to become more like a copy of the actual object.
(notice #v.2 in code)
class Prototype{ //aka. "fake object"
public: Vec3 position;
//bool isShootable; //(#v.2) //#X
//float delayBetweenShoot; //(#v.2)
//float hp; //(#v.2)
};
class Actual{ //aka. "actual object"
public: PhysicObject* rigidBody=nullptr;
//bool isShootable; //(#v.2) //#X
//float delayBetweenShoot; //(#v.2)
//float hp; //(#v.2)
};
int main(){ // simplify
Prototype prototype;
prototype.position = Vec3(1,2,3);
//^ end prototype creation
//v these lines are inside a function, but it simply works like this
PhysicObject* phy=new PhysicObject(prototype.position);
Actual actual;
actual.rigidBody=phy;
//actual.isShootable =prototype.isShootable; //(#v.2) #Y
//actual.delayBetweenShoot=prototype.delayBetweenShoot; //(#v.2)
//actual.hp =prototype.hp; //(#v.2)
gameLogic.add(actual); //roughly speaking
}
There are two bad signals (#v.2):-
1. repetitive code in Prototype
vs Actual
(#X)
2. tedious copying of fields. (#Y)
Thus, I think something start to go wrong.
This pattern may naturally cause new maintainability issues.
In the real situation, the actual2
contains another actual1
.
To adopt Prototype Pattern, I use a corresponding prototype2
inside another corresponding prototype1
:-
class Actual1{
//... some fields e.g. A1 a1; A2 a2; A3 a3;
};
class Actual2{
//... some other field e.g. B1 B2 B3
Actual1 actual1;
};
class Prototype1{
//... some fields e.g. very similar to A1 A2 A3
};
class Prototype2{
//... some other field e.g. very similar to B1 B2 B3
Prototype1 prototype1;
};
Question
- (1) Is it common that Prototype Pattern create new maintainability issues?
- (2) If yes, how to avoid it?
- (3) If no, where am I wrong (especially the style of coding)? ... or this trend (of repetitive code) is not really an issue at all (i.e. I just panic.)?
My poor solution
I think it might be a good idea to encapsulate the repetitive part into a single structure named Settings
.
class Settings{
bool isShootable;
float delayBetweenShoot;
float hp;
};
class Prototype{ //aka. "fake object"
public: Vec3 position;
Settings settings; //(#v.2)
};
class Actual{ //aka. "real object"
public: PhysicObject* rigidBody=nullptr;
Settings settings; //(#v.2)
};
However, it might increase unfavorable cohesion (i.e. glue or strong relation) between Prototype
and Actual
. Thus, it may leader to another new maintainability problem again.
You can avoid the unnecessary duplication by subclassing your 'actuals' from the prototype. For example:
Your intuition is correct in that by grouping 'common' fields together, you increase the coupling between those fields. In some sense there is a tradeoff between coupling and code duplication. It is up to you to determine what is an acceptable compromise that best suits your application.