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

时间:2014-02-20 05:25:18

标签: c++

我经历了工厂设计模式,并有一些疑问,  我在register函数中看到的代码,

他们将对象存储在map注册,第一次创建对象并将它们存储在容器类中),每当我们需要我们必须要求的对象时factory(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);
}

3 个答案:

答案 0 :(得分:0)

看起来你正在考虑“原型”和“工厂”模式的组合。工厂允许客户“注册”原型实例,这些实例可能是某些共同基础的子类。然后“getObject”方法生成所请求原型的副本。

我为“原型模式c ++”做了一个快速的Google ...以下是众多结果中的两个:

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

注意:我知道有很多方法可以改进这些代码,但我试图保持简单,以避免分散注意力。

答案 1 :(得分:0)

工厂将字符串映射存储到“创建函数”。在它的构造函数中,它注册了两个:“Big”对应Picture::Create,“Small”对应PictureInPicture::Create

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

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

所以事实上你有......

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

  • 一个工厂类 - RangeRingsFactory - 隐藏了您的特定类型(PicturePictureInPicture),因此您只需要一个按名称(“大”或“小”),不知道或关心所产生的具体对象类型。

答案 2 :(得分:0)

解决方案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

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

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

然后在创建ToSetRangeScalePicture的对象后调用PictureInPicture设置矩形:

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

最后

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