3

我在为以下场景找到简单而优雅的设计时遇到了麻烦。类Worker使用模板类Helper做一些工作。在简单的场景中,它看起来像这样:

template<typename T>
class Helper {
  public:
    void Help(T data) : m_data(data) {} //NOTICE: Copy
    T const& Data() const { return m_data; }

    T m_data;
}

class SimpleWorker {
  public:
    SimpleWorker() : m_helper(SimpleData()) {} // non-temp used in reality
    void DoWork()
    {
        m_helper.help();
    }        

    Helper<SimpleData> m_helper;
}

当模板参数更复杂并且与工人的业务领域相同时,事情对我来说变得复杂。工作人员需要使用帮助程序,但它还需要在数据对象上调用一些帮助程序甚至不知道的方法(在此设计中)。就像是:

template<typename T>
class Helper {
  public:
    Helper(T data) : m_data(data) {} //NOTICE: Copy
    T const& Data() const { return m_data; }

    T m_data;
}

class ComplexWorker {
  public:
    ComplexWorker() : m_helper(ComplexData()) {} // non-temp used in reality

    void DoWork()
    {
        m_helper.help();
        m_helper.GetData().DoSomethingComplexNotConst(); // <-------------
    }    

    Helper<ComplexData> m_helper;    
}

明显的问题是我不能在Data()结果上调用 not const 函数。制作Data()非常量似乎是一个坏主意,因为Helper它也用于不同的上下文中。我的目标是找到一种优雅的方式来ComplexData使用它的成员函数进行更改,ComplexWorker 首先ComplexData需要更改,以便Helper可以继续使用更改后的数据。

编辑:更改Helper构造以复制提供的数据以更好地类似于实际流程

4

3 回答 3

1

我认为最好Helper只使用静态函数,而不是维护状态(因为您在自己的代码中创建临时函数ComplexData()ComplexWorker。根据是否需要修改,通过引用或 const-reference 传递数据。

// primary template
template<typename T>
class Helper {
public:
    static void help(T const& data) const {} // non-modifying
};

// specialization for ComplexData
template<>
class Helper<ComplexData> {
public:
    static void help(ComplexData const& data) const { } // non-modifying

    static void DoSomethingComplexNotConst(ComplexData& data) // modifying
    {
         // your implementation here
    }
};

class ComplexWorker {
public: 
    ComplexWorker() : m_data(ComplexData()) {} // create new data

    void DoWork()
    {
        Helper<ComplexData>::help(m_data);
        Helper<ComplexData>::DoSomethingComplexNotConst(m_data); // <--- now no problem
    }

   private:
       ComplexData m_data;         
};

请注意,ComplexData. 有一些代码重复,help()但您可以轻松地将其提取到一个常见的非成员帮助函数中。

于 2012-08-14T11:24:11.963 回答
0

在我看来,这取决于Helper实际在做什么。您的示例仅提供了一个构造函数和一个访问器,但我怀疑这就是它在实践中所做的一切。

您是否考虑过简单地使用继承?您的Helper模板将如下所示:

template<typename T>
class Helper : public T {
    Helper(T data) : T(data) {}
    void Help() {};
}

在这种情况下,您可以Helper<ComplexData>直接在“is-a”关系中使用该对象:

class ComplexWorker {
    Helper<ComplexData> m_helper;

    void DoWork()
    {
        m_helper.help();
        m_helper.DoSomethingComplexNotConst();
    }        
}
于 2012-08-14T11:24:23.103 回答
0

为什么不参考STL中Container部分的实现。Data() 函数的重载可以在安全和优雅之间取得平衡。

template <typename T>
class Helper {
public:
    Helper(T data) : m_data(data) {} //NOTICE: Copy
    T const& Data() const { return m_data; }
    T& Data() {return m_data; }
private:
    T m_data;
}

class ComplexWorker {
public:
    ComplexWorker() : m_helper(ComplexData()) {} // non-temp used in reality

    void DoWork()
    {
        m_helper.help();
        ComplexData &cd1 = m_helper.Data();
        cd1.QuerySth();
        const ComplexData &cd2 = m_helper.Data();
        cd2.ModifySth();
    }    
private:
    Helper<ComplexData> m_helper;    
}
于 2012-08-14T17:40:49.687 回答