【问题标题】:How to specify the type for factory objects如何指定工厂对象的类型
【发布时间】:2012-03-07 19:12:17
【问题描述】:

我有一个模型视图架构。我想从模型对象创建一个视图对象。 这是一个基本示例。

我如何指定模型对象的类型:枚举(但它们不可扩展)、整数(但很容易搞砸)...

class ModelA
{
    ModelA(int a);
}

class ModelB : public ModelA
{
    ModelB(int a,int b);
}

class ViewModelA
{
    ViewModelA(ModelA* ma);
}

class ViewModelB : public ViewModelA
{
    ViewModelB(ModelB* mb);
}

class ViewFactory
{
     ModelA * createFromModel(ModelA *ma)
     {
          // Now what is the best way to store type ???
          // Used an integer and overload a static method getType()
          // Or use an enum?
          switch(ma.type)
          {

          }
     }
}


int main(int argc, char *argv[])
{
    ModelA *ma = new ModelA(10);
    ModelA *mb = new ModelB(10,11); 
    ViewFactory myFactory;
    ViewModelA *va = myFactory.createFromModel(ma);
    ViewModelB *vb = myFactory.createFromModel(mb);
    //va should be a model of ViewModelA and vb a model of ViewModelB
}

【问题讨论】:

  • 这里为什么不直接使用多态,而不是存储类型和switch语句呢?您的 createFromModel 函数只会调用 ModelA 指针上的成员函数,并且会多态地选择适当的函数。

标签: c++ design-patterns types factory


【解决方案1】:

恕我直言,根据您的问题和对其他答案的评论,您也可以在此处使用Visitor pattern。 阅读它herehere

因此,Visitor 将访问模型层次结构。 Visitor 的职责是为访问的 Model 类型创建适当的 View 对象。

那么你就不需要存储/声明模型类型了。

工作代码:也住在这里:http://ideone.com/9A5bJ

#include <iostream>



class Visitor{
public:
    virtual ~Visitor(){}
    virtual void visitModelA(class ModelA*) = 0;
    virtual void visitModelB(class ModelB*) = 0;
    //add visit functions for later defined models

};





class View{
public:
    virtual ~View(){}
};

class ViewA : public View{
public:
    ViewA(){
        std::cout << "Created ViewA\n"; 
    }
};


class ViewB : public View{
public:
    ViewB(){
        std::cout << "Created ViewB\n"; 
    }
};








class Model{
public:
    virtual ~Model(){}

    virtual void Accept(Visitor* visitor) = 0;

};

class ModelA:public Model{
public:

    virtual void Accept(Visitor* visitor){
        visitor->visitModelA(this);
    }
};

class ModelB:public Model{
public:
    virtual void Accept(Visitor* visitor){
        visitor->visitModelB(this);
    }
};






// ViewCreator can be made a private class of ViewFactory
class ViewCreator : public Visitor{
public:
    virtual void visitModelA(class ModelA*) {
        _view = new ViewA();
    }
    virtual void visitModelB(class ModelB*) {
        _view = new ViewB();
    }

    //add visit functions for later defined models

    View* GetView(){
        return _view;
    }   

private:
    View* _view;
};


class ViewFactory{
public:
    static View* CreateViewFor( Model* model){
        ViewCreator viewCreator;
        model->Accept(&viewCreator);
        return viewCreator.GetView();
    }

};


int main(){

    ModelA modelA;
    View* viewA = ViewFactory::CreateViewFor(&modelA);


    ModelB modelB;
    View* viewB = ViewFactory::CreateViewFor(&modelB);



}

【讨论】:

  • 对我来说似乎有点矫枉过正。另外,我必须在模型中添加额外的数据,因为我必须在模型中保留指向访问者的链接。
  • 也许吧。你不需要在Model中保留额外的数据,你需要添加一个Accept function()。
  • 像魅力一样工作。一个小缺点是,每次我需要创建视图对象时,我都必须创建一个 FactoryObject(因为 _view 可以在我的多线程应用程序中更改),但在其他方面就像一个魅力。
  • 很高兴为您提供帮助。您可以(应该?)将 Factory 的 Create() 函数设为静态,因此无需创建 FactoryObject。
  • 问题来自 View* GetView()。如果您有 2 个以上的线程访问该对象,则第一个线程可能会创建 _view 对象。但随后第二个线程可能会在第一个线程得到它之前更改 _view 对象。锁定和解锁将是一个真正的痛苦。
【解决方案2】:

您需要所有类型的接口:

class ModelIface
{
}
class ModelA : public ModelIface
{
    ModelA(int a);
}

class ModelB : public ModelIface
{
    ModelB(int a,int b);
}

class ViewIface
{
}
class ViewModelA : public ViewIface
{
    ViewModelA(ModelIface* ma);
}

class ViewModelB : public ViewIface
{
    ViewModelB(ModelIface* mb);
}

class ViewFactory
{
     ViewIface * create(ModelIface *ma)
     {
          switch(ma.type)
          {
             case TYPE1:
               return new ViewModelA(ma);
             case TYPE2:
               return new ViewModelB(ma);
             default :
               ;
          }
          return nullptr;
     }
}

TYPE1 和 TYPE2 是 int 还是 enum 无关。

int main(int argc, char *argv[])
{
    ModelIface *ma = new ModelA(10);
    ModelIface *mb = new ModelB(10,11); 
    ViewFactory myFactory;
    ViewModelIface *va = myFactory.createFromModel(ma);
    ViewModelIface *vb = myFactory.createFromModel(mb);
    //va should be a model of ViewModelA and vb a model of ViewModelB
}

【讨论】:

  • 问题是如果使用枚举作为类型,我将不得不将它存储在基类中(在 ModelInterface 中),所以每次我将向模型层次结构中添加一个新类时,我必须修改ModelInterface,我担心重新编译会很长......
  • @Anton 不,为什么需要将它存储在基类中?您可以将其存储在单独的标头中,并且在 c++11 中您可以使用强类型枚举和枚举前向声明。
  • 我不确定 MinGW gcc 是否符合 c++11 标准,这就是为什么我认为我不能使用枚举的前向声明。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-10
  • 2022-07-08
  • 2020-01-29
相关资源
最近更新 更多