Is breaking circular dependency necessary in this case?

128 views Asked by At

for example , consider a system , which has a global main controller that has a sub controller , and the sub controller may call main controller to update:

MainController.h

class SubController;
class MainController{
public:
    static void setGlobalMainController(MainController* mainController);
    static MainController* getGlobalMainController();
    void init();
    void updateSystem();
protected:
    SubController* subController;
};

MainController.cpp

#include "MainController.h"
#include "SubController.h"
MainController* globalMainController;
void MainController::setGlobalMainController(MainController* mainController){
    globalMainController=mainController;
}

MainController* MainController::getGlobalMainController(){
    return globalMainController;
}

void MainController::init(){
    this->subController=new SubController();
    //wait sub controller to press button...
}

void MainController::updateSystem(){
    //do something
}

SubController.h

class SubController{
protected:
    void onButtonPressed();
}

SubController.cpp

#include "SubController.h"
#include "MainController"
void SubController::onButtonPressed(){
    //do something...
    MainController::getGlobalMainController()->updateSystem();
}

the SubController may accept button event and then need to update the main controller.

It has circular dependency,then I tried to break circular dependency using inheritance: create a new class MainControllerImp and move all concrete method in MainController to MainControllerImp:

MainController.h

class SubController;
class MainController{
public:
    static void setGlobalMainController(MainController* mainController);
    static MainController* getGlobalMainController();
    virtual void init()=0;
    virtual void updateSystem()=0;
protected:
    SubController* subController;
};

MainController.cpp

#include "MainController.h"
#include "SubController.h"
MainController* globalMainController;
void MainController::setGlobalMainController(MainController* mainController){
    globalMainController=mainController;
}

MainController* MainController::getGlobalMainController(){
    return globalMainController;
}

MainControllerImp.h

#include "MainController.h"
class MainControllerImp : public MainController{
    virtual void init();
    virtual void updateSystem();
}

MainControllerImp.cpp

#include "MainControllerImp.h"
void MainControllerImp::init(){
    this->subController=new SubController();
    //wait sub controller to press button...
}

void MainControllerImp::updateSystem(){
    //do something
}

SubController.h

class SubController{
protected:
    void onButtonPressed();
}

SubController.cpp

#include "SubController.h"
#include "MainController"
void SubController::onButtonPressed(){
    //do something...
    MainController::getGlobalMainController()->updateSystem();
}

the circular dependency seems disappeared. But after some time, I start thinking if I need breaking dependency at this case: it only moves all methods from parent class to child class, besides that it seems no any benefits. Also, it has one more class, which is less readable and the code is less straight forward.

Should I leave circular dependency at this case? or there are other better design pattern to break circular dependency?

1

There are 1 answers

0
BЈовић On

Circular dependency is always bad, and I would always try to remove it.

Why? Because it makes code fragile, and it directly breaks the open/close principle. If you have to modify one class, then there are 99% chances that you will have to modify the other class as well.

There are few options to break the circular dependency, but my favorite method (I think from "Large-Scale C++ Software Design") is to merge two classes into one.