使用工厂时解决循环依赖关系

时间:2017-05-22 22:08:26

标签: c++ recursion factory circular-dependency

我有以下配置来评估并使用工厂根据类型将对象获取到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;
}

3 个答案:

答案 0 :(得分:1)

工厂不需要知道子类型,只需要能够新建一个子类型。一种方法是使用Creator类,其作用是将具体对象的创建委托给类本身。

我在这里使用std::string作为名称,但您可以轻松使用intOperation枚举。

类似的东西:

#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确保标题只包含一次。始终将此作为标题中的第一行。