c++设计:减少深层类层次结构中的耦合

c++ design: reducing coupling in a deep class hierarchy

本文关键字:层次结构 耦合 设计 c++      更新时间:2023-10-16

请考虑这个类层次结构:

#include <iostream>
struct Base
{    
    Base(int arg1, int arg2, int arg3, int arg4)
    {
        std::cout << "Base::Base:" << arg1 << "," << arg2 << "," << arg3 << "," << arg4 << std::endl;
    }
    void BaseDoWork()
    {
        std::cout << "Base::BaseDoWork" << std::endl;
    }
};
struct Derived1:public Base
{
    Derived1(int arg1, int arg2, int arg3, int arg4):Base(arg1, arg2, arg3, arg4){}
    void DerivedDoWork()
    {
        BaseDoWork();
    }
};
struct Derived2:public Derived1
{
    Derived2(int arg1, int arg2, int arg3, int arg4):Derived1(arg1, arg2, arg3, arg4){}
};
int main(int argc, char *argv[])
{
    Derived2 myDerived2(1,2,3,4);
    myDerived2.DerivedDoWork();
    return 0;
}

Derived1类具有比我希望的更多的耦合性:它必须知道如何构造"Base"类。在深层层次结构中,这意味着在类层次结构中一直传播"Base"类构造函数的参数。更改"Base"类构造函数需要更改所有派生类。

我对这个类层次结构的目标是:

  1. Derived1期望基类中有一个BaseDoWork()方法,但不需要知道如何构造基类。

  2. Derived2知道如何构造"Base"类。

理想情况下,我想让Derived1成为一个模板,接受任何带有可访问的"BaseDoWork()"方法的基类,如下所示:

template <T> struct Derived1:public T
{
    void DerivedDoWork()
    {
        BaseDoWork();
    }
};

但是,如果我将上面的模板实例化为Derived1<Base>,如果不向Derived1添加"Base"构造函数参数的知识,我就看不到如何构造"Base"类。

假设这是真实的层次结构,如果Derived1Base派生的类,则必须知道如何构造父类(Base)。

正如我所理解的,也许我错了,如果Derived1实际上不是Base派生的(子)类,并且只需要知道它的接口,那么就不需要知道如何构造Base实例。因此,您可以定义Derived1如下:

struct Derived1
{
    Derived1(int arg1, int arg2, int arg3, int arg4)
    {}
    .....
};

只有Base派生类需要知道如何构造Base:

struct Derived2 : public Base
{
    Derived2(int arg1, int arg2, int arg3, int arg4) : 
        Base(arg1, arg2, arg3, arg4)
    {}
    .....
};

现在,如果Derived2真的是Derived1的子级,那么必须知道如何创建它的父级。以前的代码变为:

struct Derived2 : public Base, public Derived1
{
    Derived2(int arg1, int arg2, int arg3, int arg4) : 
        Base(arg1, arg2, arg3, arg4),
        Derived1(arg1, arg2, arg3, arg4)
    {}
    .....
};

如果必须使用Derived1中的Base::BaseDoWork()方法,则可以按如下方式定义类:

struct Base
{    
    Base(int arg1, int arg2, int arg3, int arg4)
    {
        std::cout << "Base::Base:" << arg1 << "," << arg2 << "," << arg3 << "," << arg4 << std::endl;
    }
    virtual void BaseDoWork()
    {
        std::cout << "Base::BaseDoWork" << std::endl;
    }
};
struct Derived1
{
    Derived1(int arg1, int arg2, int arg3, int arg4)
    {}
    template <typename T>
    void DerivedDoWork(T & base)  // only knows T interface
    {
      base.BaseDoWork();
    }
};
struct Derived2 : public Base, public Derived1
{
    Derived2(int arg1, int arg2, int arg3, int arg4) : 
      Base(arg1, arg2, arg3, arg4),
      Derived1(arg1, arg2, arg3, arg4)
    {}
    virtual void DerivedDoWork()
    {
      Derived1::DerivedDoWork<Base>(*(static_cast<Base *>(this)));
    }
};

Main保持不变。

可能您需要查看此层次结构。

publicBase继承Derived1时,结果是Derived1已经知道如何构造Base,所以如果你想让Derived1不知道如何构造Base,也许最好不要从Base继承它?相反,将Base分离为某种表演者。

考虑一下这段代码,我并不认为这是解决方案,但也许它会把你推向其他想法(类的名称相同):

#include <iostream>
struct Base
{
    Base()
    {
        std::cout << "Base::Base:" << std::endl;
    }
    Base(int arg1, int arg2, int arg3, int arg4)
    {
        std::cout << "Base::Base:" << arg1 << "," << arg2 << "," << arg3 << "," << arg4 << std::endl;
    }
    void DoWork()
    {
        std::cout << "Base::BaseDoWork" << std::endl;
    }
};
template <typename T>
struct Derived1
{
    T object;
    Derived1(T obj){ object = obj; }
    void DerivedDoWork()
    {
        object.DoWork();
    }
};
template <typename T>
struct Derived2 : public Derived1<T>
{
    Derived2(int arg1, int arg2, int arg3, int arg4) : Derived1( T(arg1, arg2, arg3, arg4))
    { }
};
int main(int argc, char *argv[])
{
    Derived2<Base> myDerived2(1,2,3,4);
    myDerived2.DerivedDoWork();
    return 0;
}