可以混合复合模式和奇怪的重复模板模式

Possibility to mix composite pattern and curiously recurring template pattern

本文关键字:模式 混合 复合      更新时间:2023-10-16

我有一个复合模式实现,用于GUI组件:

class CObject {
private:
  CObject * m_pParent;  
  CObjectContainer * m_pChildren;
  void private_foo() {
    this->foo();
    //Calls private_foo for each child in container.
    m_pChildren->foo();
  }
public:
  virtual void foo() {
    //empty for base class
  }
  virtual CObject * duplicate() {
    //Do duplication code
    return new CObject(*this);
  }
  virtual CObject * detach() {
    //Remove this object (along with it's children)
    //from current tree.
    m_pParent->RemoveChild(this);
    m_pParent = nullptr;
    return this;
  }
}
class CSpecificObject : public CObject {
public:
  virtual void foo() {
    //Specific code for this class
  }
  virtual CSpecificObject * duplicate() {
    //Overload, but the code only calls diferent constructor
    return new CSpecificObject(*this);
  }
  virtual CSpecificObject * detach() {
    //Note the code is identical.
    m_pParent->RemoveChild(this);
    m_pParent = nullptr;
    return this;
  }
}

不幸的是,继承类的数量迅速增加,重复的代码(在给定的示例中只有 detach() 方法)让我头疼。

有没有办法干净地实现 detach() 方法,使返回类型与调用它的对象相同?

我在考虑 CRTP,但我想不出一种方法来保持动态多态性以及编译时多态性:

template <Child>
class CObject {
private:
  ...
  Child * detach() {
    m_pParent->RemoveChild(this);
    m_pParent = nullptr;
    return static_cast<Child*>(this);
  }
  ...
}
//Array of CObject* pointers is no longer possible.

您可以添加一个抽象级别:

class CObjectBase
{
    public:
        // Other methods...
        virtual CObjectBase* detach() = 0;
        virtual CObjectBase* duplicate() const = 0;
};
template <typename Child>
class CObject : public CObjectBase
{
    public:
        // ...
        Child* duplicate() const
        {
            return new Child(*static_cast<Child*>(this));
        }
        Child* detach()
        {
            m_pParent->RemoveChild(this);
            m_pParent = nullptr;
            return static_cast<Child*>(this); // Cast needed here (inherent to CRTP)
        }
        std::vector<CObjectBase*> children; // Array possible now
        // ...
};
class MyObject : public CObject<MyObject>
{
    // ...
};

在自然语言中:所有对象的接口(CObjectBase)对其后代(CObject<Child>)都有一个部分实现,它只需要继承这个部分实现,减少复制代码的数量。

我在考虑 CRTP,但我想不出一种方法来保持动态多态性以及编译时多态性

您可以通过使用 CRTP 样式基类为某些接口提供默认虚拟实现来混合它们。

因此,您可以聚合 CRTP 基本实现(可能配置了其他"策略"模板参数),并且仍然能够覆盖继承类中的特定行为。

Microsoft的ATL库经常使用它。我还在我的 STTCL 状态机库中使用了这种技术。

仅从代码片段来看,尚不清楚为什么需要detach()返回指向已交付类型的指针。

若要利用返回已传递类型的detach(),无论如何都需要使用对已传递类型的引用来调用它。喜欢这个:

CSpecificObject* specific_object = new SpecificObject();
// ...
specific_object->detach()->method_declared_in_specific_object();

但这可以用即使分离无效也能工作的等效项替换:

specific_object->detach();
specific_object->method_declared_in_specific_object();

如果引用了基类型,则无法利用detach()返回类型:

CObject* specific_object = new SpecificObject();
//...
// !!! Won't compile:
specific_object->detach()->method_declared_in_specific_object(); 

出于这个原因,目前尚不清楚您尝试实施的方法的优势是什么。

一面不是duplicate()方法很臭。当传递的类不覆盖它,但使用父类的默认实现时,它会中断。这可能表明高级设计有问题。