我正在学习设计模式,并尝试自己实现。对于大多数设计模式,我都可以理解那里的用法和实现,但是我对原型(prototype)模式感到困惑。这是我的实现方法。

Ship.h

class IShipPrototype
{
public:
    virtual IShipPrototype* clone() = 0;

    IShipPrototype(const std::string sName, float w = 10, float h = 10, float s = 10) : shipName{ sName }, width{ w }, height{ h }, speed{ s } {};
    IShipPrototype(const IShipPrototype &that)
    {
        shipName = that.shipName;
        width = that.width;
        height = that.height;
        speed = that.speed;
    }

    void Print()
    {
        std::cout << "-----------------------\n";
        std::cout << "\tShip Info\t\n" <<
            "Name:\t\t" << shipName << "\n" <<
            "Width:\t\t" << width << "\n" <<
            "Height:\t\t" << height << "\n" <<
            "Speed:\t\t" << speed << std::endl;

    }
    void SetShipName(const std::string &newShipName)    { shipName = newShipName; }
    void SetShipHeight(float NewHeight)         { height = NewHeight; }
    void SetShipWidth(float NewWidth)           { width = NewWidth; }
    void SetShipSpeed(float NewSpeed)           { speed = NewSpeed; }


private:
    std::string shipName;
    float width = 0, height = 0, speed = 0;
};


class Ship : public IShipPrototype
{

public:
    Ship(const std::string& sName, float w, float h, float s) : IShipPrototype(sName, w, h, s) {}
    Ship(const Ship &ship) : IShipPrototype(ship) {}


    IShipPrototype* clone() override
    {
        return new Ship(*this);
    }

};


class ShipFactory
{
public:
    ShipFactory()
    {
        ships[0] = new Ship("titanic", 12, 43, 47);
        ships[1] = new Ship("Black pearl", 15, 73, 24);
        ships[2] = new Ship("Man O War", 32, 46, 14);
        ships[3] = new Ship("Rose Marry", 24, 53, 52);
    }

    IShipPrototype* CreateCloneShip(int idx)
    {
        return ships[idx]->clone();
    }

private:
    std::map<int, IShipPrototype*> ships;

};

main.cpp
int main()
{
    ShipFactory *factory = new ShipFactory();
    IShipPrototype* titanicClone = factory->CreateCloneShip(0);
    IShipPrototype* blackPearlClone = factory->CreateCloneShip(1);
    IShipPrototype* manOwarClone = factory->CreateCloneShip(2);
    IShipPrototype* roseMarry = factory->CreateCloneShip(3);

    titanicClone->SetShipName("titanicClone");
    titanicClone->SetShipHeight(100);
    titanicClone->Print();

    blackPearlClone->SetShipName("blackPearlClone");
    blackPearlClone->SetShipSpeed(10);
    blackPearlClone->Print();

    manOwarClone->SetShipName("manOwarClone");
    manOwarClone->SetShipWidth(40);
    manOwarClone->Print();

    roseMarry->SetShipName("roseMarry");
    roseMarry->SetShipSpeed(130);
    roseMarry->Print();

    getchar();
    return EXIT_SUCCESS;
}

令我感到困惑的部分是克隆函数返回接口(interface)的指针,这意味着我无法将克隆存储在其他船对象中,例如。 Ship* ship = factory->CreateCloneShip(0);

我认为这种设计模式背后的想法是创建一个已经存在的对象的克隆,然后更改它的一些细节。
是我的实现不正确还是我错过了什么?

最佳答案

原型(prototype)模式允许我们通过调用虚拟成员函数来多态地创建对象的拷贝,该函数通常在您的代码中称为clone(),



通常,覆盖函数必须与其覆盖的虚函数的类型完全相同。但是,如果要覆盖的虚函数返回(原始)指针或引用,则对于允许覆盖函数返回的类型有一些约束放松。

在这种情况下,重写函数的返回类型可以是指针或对重写函数返回指针的类类型的派生类的引用。这称为方法的covariant return type

现在,请牢记这一点,并将重点放在IShipPrototype::clone()虚拟成员函数上。它返回一个IShipPrototype*:

class IShipPrototype {
public:
   virtual IShipPrototype* clone() = 0; // returns IShipPrototype*
// ...
};

由于IShipPrototypeShip的公共(public)基础,因此覆盖的Ship::clone()可以返回Ship*而不是IShipPrototype*:
class Ship: public IShipPrototype {
public:
   Ship* clone() override; // returns Ship*
// ...
};

这样,如果您有一个Ship对象,并直接在其上调用clone(),则将获得一个Ship*而不是IShipPrototype*-尽管Ship*确实隐式转换为IShipPrototype*,因为IShipPrototypeShip的公共(public)基类。此处的IShipPrototypeShip被称为协变类型。

请注意,如果您通过clone()接口(interface)调用IShipPrototype,则返回的指针指向的类型的静态类型为IShipPrototype*。但是,如果在Ship实例上调用了动态类型,则该类型将为Ship

09-08 11:24