1

提前感谢您的阅读。这是一个挑剔的设计问题,因为我有一个足够的解决方案,但如果没有更好的模板方式,我对此不是很有经验。

我需要存储一系列类型的数据表(派生自抽象类 DataTable)。我编写了一个“DataTableIndex”抽象类,它存储一个向量 DataTable* 并处理所有 DataTableIndexes 共有的一般工作——进行查找、实现代理模式以便仅在需要时加载表、错误检查等。

然后我为每个表类型子类化它,我需要这样做的唯一原因是因为每个表类型都有一个特定的函数可以调用来加载它。

如果可能的话,我想通过模板以某种方式避免这种 DataTableIndex 的子类化,因为 DataTable 有很多子类。

class DataTableIndex
{  
  // various functions to implement lookup, Proxy and error checking
  //   functionality common to all DataTableIndexes.
  // This code needs access to _lookupTable and _theTables

  DataTable* getTable( int tableNum );

private:
  // These functions call the appropriate user interface function for loading
  //   a table of the subclass' type.
  //   They are called by more general non-virtual public functions
  virtual bool loadIndex( vector<LookupEntry*>& returnLookupTable ) = 0;
  virtual DataTable* loadTable( int tableNum ) = 0;

  vector<LookupEntry*> _lookupTable;
  vector<DataTable*>   _theTables;

  UserInterface* UI;
};  

这个类有非常简单的子类,它们基本上指向用户界面类中实际打开和解析数据表文件的函数。

class TableTypeA_Index : public DataTableIndex
{
  virtual bool loadIndex( vector<LookupEntry*>& returnLookupTable )
  {
     return UI->loadTableAIndex( _lookupTable );
  }

  virtual DataTable* loadTable( int tableNum )  
  { 
     return UI->loadTableTypeA( _lookupTable[ tableNum ] );
  }

};

这工作得很好。但我觉得我应该能够通过模板参数将“loadTableTypeA”例如传递给 DataTableIndex,所以我不必对它进行子类化。

我想使用模板的另一个原因是我不想一直将 DataTable* 强制转换为实际的表类型。即使我在编译时知道它应该是什么类型的表,我觉得我应该使用 dynamic_cast<> 进行错误检查,但我不希望 getTable() 的调用者每次都必须这样做(它经常被调用)。

我理想的解决方案是: 1) 将 DataTableIndex 类泛化为模板,用模板参数替换 _lookupTable 和 _theTables 中的 LookupEntry* 和 DataTable*。这将消除铸造。

2) 映射适当的 UI 函数以加载正确的表类型,无需子类化。

所以基本上我想使用这个类看起来像这样(不知何故)

DataTableIndex< LookupEntryTypeAMatlab, 
                TableTypeA, 
                loadTableAIndex(),
                loadTableTypeA() > theTypeAIndex;

我对策略类进行了一些思考,但我对这种方法的印象是,在这种情况下,我只是将子类化移动到其他东西。

4

2 回答 2

1

一般来说,这可以通过使用策略模式来完成。这可以使用简单的组合来实现,因此不需要模板。但是,您仍然需要为每种不同的表类型定义一个特殊的策略。这将需要子类化:

class LoadTableStrategy {
public:
    virtual bool loadIndex( vector<LookupEntry*>& returnLookupTable ) = 0;
    virtual DataTable* loadTable( int tableNum ) = 0;
};

这个类必须是每个表类型的子类。DataTableIndex然后将在构造函数中接收一个实例LoadTableStrategy,并使用它来加载数据,而不是私有虚函数。

您当然可以将策略类型作为模板参数传递,但请注意,这是缺点。使用不同模板参数实例化的两个DataTableIndex将是编译器的不同类型。除非您创建特定的重载,或者使该函数成为函数模板本身,否则您将无法定义一个可以同时处理这两者的函数。

于 2011-03-09T09:40:53.240 回答
0

如果你想坚持使用模板,你可以TableTypeA_Index变成一个模板,但是你必须将指向 UserInterface 的成员函数的指针传递给构造函数。例如:

typedef bool (UserInterface::*LoadTableIndexFP) (vector<LookupEntry*>&);
typedef DataTable* (UserInterface::*LoadTableTypeFP) (LookupEntry*);

template<class TABLE>
class TableType_Index : public DataTableIndex
{
public:
    TableType_Index (LoadTableIndexFP loadTableIndexFP, LoadTableTypeFP loadTableTypeFP)
        : loadTableIndexFP (loadTableIndexFP)
        , loadTableTypeFP (loadTableTypeFP)
    {
    }

    virtual bool loadIndex( vector<LookupEntry*>& returnLookupTable )
    {
        return (UI->*loadTableIndexFP) (returnLookupTable);
    }

    virtual DataTable* loadTable( int tableNum )
    {
        return (UI->*loadTableTypeFP) (_lookupTable[ tableNum ]);
    }

private:
    LoadTableIndexFP loadTableIndexFP;
    LoadTableTypeFP loadTableTypeFP;
};

int main (int argc, char* argv[])
{
    TableType_Index<TableA> (&UserInterface::loadTableAIndex, &UserInterface::loadTableTypeA);

    return 0;
}

我没有添加LookupEntryTypeAMatlab为模板参数,因为从您的TableTypeA_Index定义中不清楚它的作用是什么。

请注意,将 ptr-to-mem-funs 传递给 ctor 的另一种方法是为每个表类型设置一个特征类:

template<typename T>
struct TableTraits
{
};

template<>
struct TableTraits<TableA>
{
    static LoadTableIndexFP loadTableIndexFP;
    static LoadTableTypeFP loadTableTypeFP;
};

LoadTableIndexFP TableTraits<TableA>::loadTableIndexFP = &UserInterface::loadTableAIndex;
LoadTableTypeFP TableTraits<TableA>::loadTableTypeFP = &UserInterface::loadTableTypeA;

template<class TABLE>
class TableType_Index : public DataTableIndex
{
public:
    virtual bool loadIndex( vector<LookupEntry*>& returnLookupTable )
    {
        return (UI->*TableTraits<TableA>::loadTableIndexFP) (returnLookupTable);
    }

    virtual DataTable* loadTable( int tableNum )
    {
        return (UI->*TableTraits<TableA>::loadTableTypeFP) (_lookupTable[ tableNum ]);
    }
};

虽然这两种方法都不理想...

于 2011-03-09T18:45:11.947 回答