我有以下配置来评估并使用工厂根据类型将对象获取到MathOperation的子类。
class MathOperation {
Operation GetOperationType();
int Evaluate (config c);
}
config {
type = min
config {
type = average
int x
int y
}
config {
type = sum
int p
int q
}
...
}
例如,如果x = 10,则y = 20,p = 10,q = 2 答案是min(平均值(10,20),总和(10,2))= 12。
我遇到了一个循环依赖问题,因为MathOperation的每个子类都需要包含工厂来评估它的子配置,而工厂ofcoruse需要包含MathOperation的每个子类。我该如何解决这个问题? 这就是我目前所拥有的:
MathOperationFactory.h和cc
#include "average.h"
#include "min.h"
#include "sum.h"
std::unique_ptr<MathOperationObject> MakeObject(OperationType type) {
switch(type) {
case min : return MinOperation();
...
}
}
MinOperation.h和cc
#include "mathoperationfactory.h"
int Evaluate(Config c) {
int minimum = 1000; // large number.
ASSERT(config.type = min);
for(config : c) // repeated configs {
type t = c.type;
factory.MakeObject(t);
if(t.Evaluate < minimum) {
minimum = t;
}
}
return minimum;
}
答案 0 :(得分:1)
工厂不需要知道子类型,只需要能够新建一个子类型。一种方法是使用Creator类,其作用是将具体对象的创建委托给类本身。
我在这里使用std::string
作为名称,但您可以轻松使用int
或Operation
枚举。
类似的东西:
#pragma once
#include <string> //
#include <map>
#include <typeinfo>
class MathOperation;
/************************************************************************/
/* MathOperation Factory */
/************************************************************************/
// Abstract Interface Type For Creator
struct CMathOperationCreator
{
virtual MathOperation* Create() = 0;
virtual ~CMathOperationCreator() {}
};
// Creator Map
std::map<std::string, CMathOperationCreator*, StringLessNoCaseCHAR>& GetMathOperationFactoryMap();
// Templated concrete creator, to be registered in the header of the concrete mathop type
template<class Derived>
struct CMathOperationConcreteCreator: public CMathOperationCreator
{
CMathOperationConcreteCreator(const std::string& theMathOperationTypeId)
{
auto aFactoryItem = GetMathOperationFactoryMap().find(theMathOperationTypeId);
if(aFactoryItem != GetMathOperationFactoryMap().end())
{
if(typeid(*aFactoryItem->second) == typeid(*this)) // avoid duplicates
return;
}
GetMathOperationFactoryMap()[theMathOperationTypeId] = this;
}
virtual MathOperation* Create() {return new Derived();}
};
//Factory Method
MathOperation* CreateMathOperation(const std::string& theMathOperationTypeId);
/**
* Macro to automatically register a MathOperation Type
*/
#define REGISTER_MathOperation( ConcreteMathOperation, name ) \
static CMathOperationConcreteCreator<ConcreteMathOperation> ConcreteMathOperation##Creator(name);
CPP档案:
// This is dumb, you don't have to do this, you just need a singleton factory that holds this map
std::map<std::string, CMathOperationCreator*, StringLessNoCaseCHAR>& GetMathOperationFactoryMap()
{
static std::map<std::string, CMathOperationCreator*, StringLessNoCaseCHAR> theMap;
return theMap;
}
MathOperation* CreateMathOperation( const std::string& theMathOperationTypeId )
{
auto aFactoryItem = GetMathOperationFactoryMap().find(theMathOperationTypeId);
if (aFactoryItem != GetMathOperationFactoryMap().end())
{
MathOperation* aObject = aFactoryItem->second->Create();
return aObject;
}
return NULL;
}
注册课程:
class MinOperation : public MathOperation {
Operation GetOperationType();
int Evaluate (config c);
};
REGISTER_MathOperation(MinOperation, "min");
然后,当您解析令牌时,可以向工厂查询操作:
MathOperation* pOp = CreateMathOperation(token.lowercase());
答案 1 :(得分:0)
正如评论中指出的那样,如果没有真正的代码,很难确定。但是,最有可能的问题是你在头文件中放了太多包含。如果您只是在cc文件中添加#include "mathoperationfactory.h"
,那么您应该没问题。
此外,您需要使用包含警卫。
答案 2 :(得分:0)
#pragma once
确保标题只包含一次。始终将此作为标题中的第一行。