Good design for delegating template-member functionality

自作多情 提交于 2019-12-23 19:20:05

问题


I am having trouble in finding simple and elegant design for the following scenario. Class Worker uses template class Helper to do some work. In the simple scenario it looks like this:

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;
}

Things get complicated for me when the template argument is more complex and is of the same business domain of the worker. The worker needs to use the helper but it would also need to call some methods on the data object that the helper doesn't even know about (in this design). Something like:

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;    
}

The obvious problem is that I can't call not const function on Data() result. Making Data() non-const seems like a bad idea as Helper is used in different contexts as well. My goal is to find an elegant way to alter ComplexData using its member functions from ComplexWorker The ComplexData needs to be altered in the first place so that Helper can continue working with the altered data.

EDIT: Changed Helper construction to copy the provided data to better resemble actual flow


回答1:


I think it's best to let Helper have only static functions, not maintaing state (as you create temporary ComplexData() in ComplexWorker in your own code). Pass the data by reference or const-reference depending on whether you need to modify or not.

// 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;         
};

Note that I made a template specialization for the ComplexData. There is some code duplication in help() but you can easily extract this into a common non-member helper function.




回答2:


Seems to me that it depends on what Helper is actually doing. Your example just gives a constructor and an accessor but I doubt that is all it does in practice.

Have you considered simply using inheritance? Your Helper template would then look like this:

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

In this case you could use the Helper<ComplexData> object directly in an 'is-a' relationship:

class ComplexWorker {
    Helper<ComplexData> m_helper;

    void DoWork()
    {
        m_helper.help();
        m_helper.DoSomethingComplexNotConst();
    }        
}



回答3:


Why not refer to the realization of the Container part in STL. An overload of the Data() function may achieve a ballance between safty and elegance.

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;    
}


来源:https://stackoverflow.com/questions/11951071/good-design-for-delegating-template-member-functionality

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!