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

时间:2013-11-22 09:15:01

标签: c++ coupling

请考虑此类层次结构:

#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知道如何构建“基础”类。

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

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

    但是,如果我将上述模板实例化为Derived1<Base>,我无法在不向Derived1添加“Base”构造函数参数知识的情况下看到如何构造“Base”类。

2 个答案:

答案 0 :(得分:1)

假设这是真正的层次结构,如果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)
    {}

    .....
};

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

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保持不变。

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

答案 1 :(得分:1)

当您从public进行Derived1的{​​{1}}继承时,结果是Base已经知道如何构建Derived1,所以如果您需要{ {1}}不知道如何构建Base,也许最好不要从Derived1继承它?相反,将Base分开作为某种表演者。

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

Base