原型模式导致"actual object"和"prototype"之间的代码重复

Prototype Pattern causes code repetition between "actual object" and "prototype"

本文关键字:之间 代码 prototype object 模式 actual 原型      更新时间:2023-10-16

在将原型模式中采用后,它宜人提高了我的代码的可维护性。

但是,我开始担心实际对象变得更加细节化时,
我倾向于编码对应的原型更像是实际对象的副本。

(代码中的通知#v.2)

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
}

有两个不良信号(#v.2): -
1. Prototype中的重复代码与Actual(#X)
2.乏味的田野复制。(#Y)

因此,我认为有些事情开始出问题。
这种模式自然会引起新的可维护性问题。

在实际情况下,actual2包含另一个actual1
要采用原型模式,我在另一个相应的prototype1中使用相应的prototype2: -

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;
};

问题

  • (1)常见的是原型模式创建新的可维护性问题吗?
  • (2)如果是,如何避免它?
  • (3)如果没有,我在哪里错(尤其是编码的样式)?...或这种(重复代码)的趋势根本不是一个问题(即我只是恐慌。)?

我的可怜的解决方案

我认为将重复部分封装到名为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)
};

但是,它可能会增加PrototypeActual之间的不利凝聚力(即胶水或牢固的关系)。因此,它可能再次引起另一个新的可维护性问题。

您可以通过从原型中划分"实际'"来避免不必要的重复。例如:

struct Prototype {
    bool isShootable = false;
    float delayBetweenShoot = DEFAULT_DELAY;
    float hp = DEFAULT_HP;
    Vec3 position = STARTING_POSITION;
    ...
};
struct Actual : Prototype {
    PhysicObject* rigidBody;
    Actual() : Prototype(), rigidBody(new PhysicObject(position)) {}
}
int main() {
    Actual actual;
    // now you can access these methods
    if (actual.isShootable) {
        ...
    }
    ...
}

您的直觉是正确的,因为通过将"共同"字段分组在一起,您可以增加这些字段之间的耦合。从某种意义上说,耦合和代码重复之间存在权衡。由您确定最适合您申请的可接受折衷是什么。

可能使用不同类型(随后的双书保存)并不是对该设计模式的最佳解释。

有关避免双书保存并仍然具有基本想法的好处的方法,请参见下文 - 以预配合样本或模板对象,然后使用该实例来初始化许多其他实例。

class A {
    int32_t id;
    bool shootable;
    bool moveable;
    bool destructable;
public:
    // A template instance specific constructor.
    A(bool shoot, bool move, bool destruct)
        : id(-1) 
        , shootable(shoot)
        , moveable(move)
        , destructable(destruct)
   {
   }
   // One or more "real" instance constructors.
   A(int32_t idval, const A& source)
        : id(idval)
        , shootable(source.shootable)
        , moveable(source.moveable)
        , destructable(source.destructable)
   {
   }
   // ...
};
int main(int argc, const char *argv[])
{
    A kind(true,false,true);
    A instance0(1,kind);
    A instance1(2,kind);
    return 0;
}

作为上述想法的变体,您还可以存储对模板实例的引用,并且确实使用了两种类型。

class UnitType
{
    int32_t hp;
    bool ranged;
    //...
};
class Unit
{
    int32_t id;
    const UnitType *type;
    // more data
public:
    Unit(int32_t idval, const UnitType* unitType)
    : id(idval)
    , type(unitType)
    {
    }
    //...
};

当然,那么UnitType实例不应按照实例进行写作。一次,还有例如currentHp,您还有另一种复制形式可以处理。另外,您需要确保使用它的UnitType模板实例超过每个Unit实例的寿命。

相关文章: