如何使用工厂方法创建不同的对象

how to create different objects with factory methods

本文关键字:对象 创建 何使用 工厂 方法      更新时间:2023-10-16

我浏览了工厂设计模式并产生了一些疑问, 我在register函数中看到的代码,

他们将对象存储在map中(注册时,第一次创建对象并将它们存储在容器类中),每当我们需要对象时,我们必须从工厂询问(Factory::getObject("Rectangle")),这个矩形是在注册期间已经创建并存储在地图中,并且每当我调用getObject("Rectangle")时,他们都会返回此对象)。

我的怀疑是每次我只得到相同的对象,如果我想为矩形创建 10 个不同的对象,

如何创建此矩形的 10 个差异对象?

提前谢谢。

RangeRingsFactory::RangeRingsFactory()
{
    Register("Big", &Picture::Create);            //picure & picyureInPicture inherited from IRangeRings 
    Register("Small", &PictureInPicture::Create);
}
RangeRingsFactory *RangeRingsFactory::Get()
{
    static RangeRingsFactory instance;
    return &instance;
}
void RangeRingsFactory::Register(const string &Name, CreateRRFn pfnCreate)
{
    map1[Name] = pfnCreate;
}
IRangeRings *RangeRingsFactory::CreateRR(const string &Name)
{
     FactoryMap::iterator it = map1.find(Name);
            if( it != map1.end() )
                   return it->second();
            return NULL;
}

图片:

Picture::Picture():IRangeRings()
{
    setRangeScale(QRect(-200,-200,400,400));
}
IRangeRings *Picture::Create()
{
    return new Picture();
}

主要:

MainWindow::MainWindow(QWidget *parent)
: QWidget(parent)
{
    string Name1 = "Big";
    IRangeRings *p1 = RangeRingsFactory::Get()->CreateRR(Name1);
    string Name2 = "Small";
    IRangeRings *p2 = RangeRingsFactory::Get()->CreateRR(Name2);
    outerLayout = new QHBoxLayout;
    outerLayout->addWidget(p1);
    outerLayout->addWidget(p2);
    this->setLayout(this->outerLayout);
}

您似乎正在考虑"原型"和"工厂"模式的组合。 工厂允许客户端"注册"原型实例,这些实例可能是某些公共基的子类。 然后,"getObject"方法生成所请求原型的副本。

我做了一个快速的谷歌"原型模式c ++"......以下是众多结果中的两个:

http://en.wikibooks.org/wiki/C%2B%2B_Programming/Code/Design_Patterns#Prototype

http://www.codeproject.com/Articles/185348/Prototype-Design-Pattern-2

下面是一个简单的示例,使用基类shape和两个子类rectanglecircle。 这些类的作用不大,但它们具有说明模式的最小结构。

(警告:我实际上并没有编译这个,所以如果我犯了任何简单的错误,请让我休息一下!

#include <map>
// Abstract base class for all shapes
class shape
{
public:
  virtual ~shape() {}
  virtual shape* clone() const = 0;
};
// Concrete subclass of shape
class rectangle : public shape
{
public:
  virtual shape* clone() const override
  {
    return new rectangle( *this );
  }
};
// Concrete subclass of shape
class circle : public shape
{
public:
  virtual shape* clone() const override
  {
    return new circle( *this );
  }
};
class Factory
{
public:
  // Add the given prototype object to the factory
  void register( std::string name, shape* proto )
  {
    protos[name] = proto;
  }
  // Get a copy of the prototype with the given name
  shape* getObject( std::string const& name ) const
  {
    // Warning: This will throw if name is not found!
    return protos[name]->clone();
  }
private:
  // Warning: This will leak unless cleaned up in the destructor!
  std::map<std::string, shape*> protos;
};
int main()
{
  Factory fact;
  fact.register( "rectangle", new rectangle() );
  fact.register( "circle", new circle() );
  // These will be separate copies of the original prototype
  shape* rect1 = fact.getObject( "rectangle" );
  shape* rect2 = fact.getObject( "rectangle" );
  // Don't leak!
  delete rect1;
  delete rect2;
}

注意:我知道有很多方法可以改进此代码,但我尽量保持简单以避免分散关键点的注意力。

工厂存储字符串映射到"创建函数"。 在其构造函数中,它注册了其中两个:"大"对应于Picture::Create,"小"对应于PictureInPicture::Create

CreateRR方法查找给定的Name,调用相应的创建函数,并返回其结果。

只要Picture::CreatePictureInPicture::Create都产生新对象,每次调用CreateRR时都会得到一个新对象。

所以事实上你有...

  • 两个工厂函数 - Picture::CreatePictureInPicture::Create - 每个函数始终创建相同类型的对象

  • 一个工厂类 - RangeRingsFactory - 向您隐藏特定类型(PicturePictureInPicture),因此您可以简单地按名称("大"或"小")请求一个,而无需知道或关心产生的特定对象类型。

解决方案 A

如果在创建IRangeRings时设置了不同的矩形,它将在 IRangeRings中具有不同的矩形。

更改这些功能:

CreateRRFn()
IRangeRings *RangeRingsFactory::CreateRR(const string &Name)
IRangeRings *Picture::Create()

自:

CreateRRFn(QRect rect)
IRangeRings *RangeRingsFactory::CreateRR(const string &Name, const QRect &rect)
IRangeRings *Picture::Create(const QRect &rect)

然后使用 RangeRingsFactory 实例创建新IRangeRings,如下所示:

IRangeRings *p1 = RangeRingsFactory::Get()->CreateRR("Big", QRect(0, 0, 100, 100));

解决方案 B

你也可以在IRangeRings中添加一个新的纯virtual函数,(我认为IRangeRings是一个接口类),我把它命名为ToSetRangeScalePicturePictureInPicture必须实现它:

void Picture::ToSetRangeScale(const QRect &rect) { setRangeScale(rect); }
void PictureInPicture::ToSetRangeScale(const QRect &rect) { setRangeScale(rect); }

然后在创建 PicturePictureInPicture 的对象后调用 ToSetRangeScale 来设置 rect

IRangeRings *p1 = RangeRingsFactory::Get()->CreateRR("Big");
p1->ToSetRangeScale(QRect(0, 0, 100, 100));

最后

RangeRingsFactory存储Create函数的一些指针。同一函数可以创建具有相同类的不同对象。不同的函数可以创建具有不同类的不同对象。如果要更改新对象的属性,可以在创建对象时或通过 new 方法创建对象之后设置该属性。