Context
I'm attempting to design a modelling framework that is modular and easy to extend and test. (I'm trying to follow open/closed, dependency injection, and composition over inheritence principles).
I have a hierachy of model objects, which contain methods, some common to all and others specific to certain models. I also have a hierachy of estimation methods which work on various subsets of the models.
Each estimator class requires a model object, which is passed using the constructor.
While constructing the objects at compile is no problem, I'm struggling to come up with a way to do so in run-time without resorting to dynamic_casting of parent model interface in the estimator. While it works, it's potentially unsafe if an invalid combination of model and estimator are put together. I've also read that dynamic_casting is usually a sign of poor code design.
Question
Are there any standard design patterns or techniques to avoid using dynamic_cast when object composition details are only known at run-time?
Or does this suggest the object hierachy needs to be completely reworked to avoid this kind of conditional dependency between objects?
Code Example
#include <iostream>
#include <unordered_map>
class i_model {
public:
virtual double getparameter_a() = 0;
};
class i_model_A : public i_model {
public:
virtual double getparameter_b() = 0;
};
class model_A : public i_model_A {
public:
double getparameter_a() { return 4.0; };
double getparameter_b() { return 4.0; };
};
class i_model_B : public i_model {
public:
virtual double getparameter_c() = 0;
};
class model_B : public i_model_B {
public:
double getparameter_a() { return 5.0; };
double getparameter_c() { return 2.0; };
};
class i_estimator {
public:
virtual double getestimate() = 0;
};
class estimator_1 : public i_estimator {
public:
estimator_1(i_model* in) : model(dynamic_cast<i_model_A*>(in)) {};
double getestimate() { return model->getparameter_a() + model->getparameter_b(); };
private:
i_model_A* model;
};
class estimator_2 : public i_estimator {
public:
estimator_2(i_model* in) : model(dynamic_cast<i_model_B*>(in)) {};
double getestimate() { return model->getparameter_a() + model->getparameter_c(); };
private:
i_model_B* model;
};
int main()
{
int a;
int b;
i_model* model = nullptr;
i_estimator* estimator = nullptr;
std::cout << "Select model: ";
std::cin >> a;
std::cout << "\nSelect estimator: ";
std::cin >> b;
switch(a) {
case 1: model = new model_A(); break;
case 2: model = new model_B(); break;
}
switch (b) {
case 1: estimator = new estimator_1(model); break;
case 2: estimator = new estimator_2(model); break;
}
std::cout << "\nEstimator value = " << estimator->getestimate();
}
-
please don't cross-post : stackoverflow.com/questions/68402131/… "Cross-posting is frowned upon as it leads to fragmented answers splattered all over the network..."gnat– gnat07/16/2021 05:45:44Commented Jul 16, 2021 at 5:45