开发者

Is this a "recognised" OO pattern? Need sanity check!

开发者 https://www.devze.com 2023-01-08 22:47 出处:网络
Say if I want to extend the functionality of a range of objects that I cannot change - for instance for adding formatting, and don\'t want to derive a huge amount of classes to extend the functionalit

Say if I want to extend the functionality of a range of objects that I cannot change - for instance for adding formatting, and don't want to derive a huge amount of classes to extend the functionality - would the following considered bad? (I'm using int and float as an example, but in my program I have about 20 or 30 classes that will end up in a tree that will contain a generic type).

class ITreeNode
{
public:
 virtual ~ITreeNode() {}
 virtual void print() = 0;
};

template <class T>
class ObjectNode : public virtual ITreeNode
{
public:
 virtual ~ObjectNode() {}
 ObjectNode(开发者_开发百科T v)
 {
  m_var = v;
 }
 void print()
 {
  print(m_var);
 }
protected:
 void print(int i)
 {
  printf("int (%d)\r\n", m_var);
 }
 void print(float f)
 {
  printf("float (%f)\r\n", m_var);
 }
 T m_var;
};

int _tmain(int argc, _TCHAR* argv[])
{
 ObjectNode<int> tInt(5);
 ObjectNode<float> tFloat(5.5);
 tInt.print();
 tFloat.print();
 getchar();
 return 0;
}

Basically I need a tree of objects (all of the same base type) that I can call with these extended functions. Originally I was using the visitor pattern and creating a visitor class for every one extended bit of functionality I needed. This seemed very cumbersome and thought maybe the above would be better.

I thought I'd post here first as a sanity check..

Thanks in advance.


Have you considered specializing your template for each of the types you wish to print? This should work without changing the way you're calling the code - but it'll also provide some compile-time type checking to ensure that your generic type has a valid print() method.

template<>
class ObjectNode<int> : public virtual ITreeNode {
    ObjectNode(int v) : m_var(v) {}
    void print() {
        printf("int (%d)\r\n", m_var);
    }
protected:
    int m_var;
};

template<>
class ObjectNode<float> : public virtual ITreeNode {
    ObjectNode(float v) : m_var(v) {}
    void print() {
        printf("float (%f)\r\n", m_var);
    }
protected:
    float m_var;
};


It's not uncommon, no, but you might ask yourself why you're using a class at all. Why not define the additional functionality as free (non-member) functions? Then they work directly on int and float, without you needing to wrap the objects. And your code would become a lot simpler, more maintainable and readable:

void print(int i)
{
  printf("int (%d)\r\n", m_var);
}
void print(float f)
{
  printf("float (%f)\r\n", m_var);
}

int _tmain(int argc, _TCHAR* argv[])
{
  tInt = 5;
  tFloat = 5.5;
  print(tInt);
  print(tFloat);
 getchar();
 return 0;
}

There is no law that states that "your code is only object-oriented if everything is inside a class". Relying on non-member functions as much as possible might even be more object-oriented.


If you end up having one or two implementations of print for these 20-30 classes, yes, I would consider it ok. But if you end up with an ObjectNode class with 20-30 implementations of print I would say the class has dependencies more than is healthy.


This may work in your simple example, but it does not work polymorphically. That is, if you have some reference to an A, but it's actually to a derived type B, you'll still construct an ObjectNode<A> and print the thing as though it's an A, not a B. (Worse, because ObjectNode takes a T by value, it will be sliced. But that's another story.)

For polymorphism to work, you'll need the visitor pattern. But I see in your other question that you're on to that.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号