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.