¿Utiliza señales/ranuras para evitar dependencias circulares?
-
21-12-2019 - |
Pregunta
Tengo una porción poco elegante de código C++ Qt donde main crea un elemento gráfico (el padre) que crea un montón de elementos gráficos secundarios.El niño y el padre tienen que llamarse métodos entre sí, es decir.el padre necesita decirle a sus hijos que hagan algunas cosas (moverse, cambiar de color, etc.), y los niños le indicarán al padre que haga cosas a sus otros hijos.Hacer que ambos llamen a los métodos de los demás genera un código circular feo y resulta frustrante esquivar los errores C2027.¿Tendría algún sentido utilizar un sistema de señal/ranura personalizado como método de comunicación entre el niño y el padre?¿O debería mantener el rumbo con mi diseño actual e intentar resolver este tipo de errores?
Por ejemplo, este código (mi diseño actual) genera C2027:
Ventana principal:
#include "mainwindow.h"
#include "ui_mainwindow.h"
vector<Foo*> FooArray;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
scene = new QGraphicsScene(this);
ui->graphicsView->setScene(scene);
int viewwidth = ui->graphicsView->width();
...
FooArray.push_back(new Foo(5, viewwidth, scene));
FooArray[0]->loadBars();
}
Foo:
#include "Foo.h" //includes bar.h
vector<int> ActiveList;
vector<Bar*> BarArray;
Foo::Foo(int id, int w, QGraphicsScene* scene)
{
this->id = id;
this->width = w;
this->scene = scene;
}
...
void Foo::loadBars()
{
...
BarArray.resize(nitems);
BarArray[k] = new Bar(id, k, this);
BarArray[k]->setPos(...);
scene->addItem(BarArray[k]);
...
}
void Foo::doSomething()
{
...
}
Bar:
#include "Bar.h" //forward declares Foo; isn't executed until Foo exists.
Bar::Bar(int setid, int num, Foo* foo)
{
this->s = setid;
this->n = num;
this->owner = foo;
}
...
void Bar::someFunction()
{
...
owner->doSomething();
...
}
Solución
Sí, para eso precisamente están las señales y las tragamonedas.
Ahora mismo tienes Bar::someFunction()
que llama Foo::doSomething()
Lo que puedes hacer en su lugar es:
- Declarar
doSomething()
como una ranura - Haz que Bar emita una señal
somethingHappened()
- Al crear a los niños, conecte sus
somethingHappened()
señal a los padresdoSomething()
ranura
Este es un ejemplo de inyección de dependencia y le permite cambiar la clase principal por otra cosa en el futuro sin tener que cambiar. Bar
en absoluto.