解决代码中模块之间的依赖关系

时间:2014-07-27 23:22:14

标签: c++ design-patterns c++11 architecture software-design

这是一个设计问题。我正在研究复杂的客户端 - 服务器架构,其中几个模块(始终在线程中运行)是相互依赖的,并且经常在彼此之间交换信息。代码中有一个创建所有模块的入口点。在代码的早期,当模块较少时,我没有通过创建和定义它们的关系来解决任何问题。这是一个例子:

auto module1 = std::make_shared<Module1>();
auto module2 = std::make_shared<Module2>(module1);
auto module3 = std::make_shared<Module3>(module1);
auto module4 = std::make_shared<Module4>(module1, module3);
//and so on and so forth

随着模块数量的增加,将模块作为课程的一部分变得必不可少。这样我们就可以在创建moduleB之前引用moduleA中的moduleB。这种方法的问题是只是头文件中的声明是不够的。因为通过std :: make_shared创建模块的那一刻,通过另一个共享指针引用它的模块会丢失引用。所以,这段代码不起作用:

m_module1 = std::make_shared<Module1>(m_module2);
m_module2 = std::make_shared<Module2>();

std :: shared_ptr在整个代码中使用,因此我无法将其更改为其他内容。我需要另一种方法来解决这个问题。

关于如何实现这一点的任何想法?

3 个答案:

答案 0 :(得分:3)

我对您的问题的解释是,您的系统已经发生变化,您现在可以按照所需的模块创建顺序进行循环,并且您需要一种技术来打破循环。你的“这不起作用”的例子有点不清楚,但实质上似乎是在它存在之前复制它并不会打破这个循环。

最好的方法是检查代码的结构以删除循环而不是破坏它。有效创建订单的第一种方法值得保留,因为代码各部分之间的依赖关系是明确的。

但是,如果你有两个强耦合的组件,那么基本技术是:

  • 合并导致循环的模块,从而消除循环。
  • 两步创建一个模块以打破循环。

两步创建类似于:

auto m1 = std::make_shared<Module1>();
auto m2 = std::make_shared<Module2>(m1);
m1->set_module2(m2);

还有其他方法可以做到这一点,包括传递一个函数对象,传递对shared_ptr的引用,并使用方法传递一个上下文对象来检索相应的shared_ptr&lt;&gt;值。

如果有关于如何创建这些对象并相互引用的强大规则,那么编写一个正确执行该函数然后返回对象的自由函数或静态成员函数也很有用。该函数可以具有模块的实现知识,但函数的用户可以只调用它。

答案 1 :(得分:2)

解决强依赖性的另一种方法是使用消息系统。 声明这样的接口。

struct IModule
{
    virtual void ReceiveMessage(shared_ptr<const IMessage>);
    void SendMessage(shared_ptr<IModule> pmodule, shared_ptr<const IMessage>)
    {
        pmodule->ReceiveMessage(msg);
    }
}

让所有模块继承此接口,并定义自己处理消息的方法

class Module : public IModule
{
public:
    void ReceiveMessage(shared_ptr<const IMessage> msg) override
    {
        switch (msg->GetType())
        {
            case MSG_PROCESSING_DATA:
                this->ProcessData(msg->GetData())
        }
    }

    void ProcessData(shared_ptr<DataType> data)
    {
        // original API for other modules to access this one
    }
}

模块不需要彼此认识。定义了。

目前尚不清楚你对依赖的主要担忧是什么。这个答案假设您在编写模块cpp时不想包含其他模块的定义。

答案 2 :(得分:0)

这是一个更简单的解决方案。假设我们有一个类Car,它在其构造函数中使用Wheel对象。我们声明Wheel对象,但不初始化。然后我们通过传递对Wheel对象的引用来初始化Car对象。然后我们创建轮对象。因为Car将Wheel存储为指向std :: shared_ptr的指针,所以这成为可能:

class Wheel
{
private:
    int m_diameter;
public:
    Wheel(int diameter) : m_diameter(diameter)
    {

    }

    int GetDiameter()
    {
        return m_diameter;
    }
};

class Car
{
private:
    int m_startSpeed;
    std::shared_ptr<Wheel> *m_wheel;
public:
    Car(int startSpeed, std::shared_ptr<Wheel>* wheel) 
        : m_startSpeed(startSpeed), m_wheel(wheel)
    {

    }

    void Accelerate(int delta)
    {
        m_startSpeed += delta;
    }

    int GetDiameter()
    {
        return (*m_wheel)->GetDiameter();
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    std::shared_ptr<Wheel> wheel;
    auto car = std::make_shared<Car>(10, &wheel);
    wheel = std::make_shared<Wheel>(50);

    int wheelDiameter = car->GetDiameter();
    return 0;
}