samedi 30 juillet 2022

Storing a derived type that will later be created

I have a set of derived Components (logical components, eg And, OR, Wire) from the base class Components.

In my application I want to store the Component Type that is currently selected. I started with the simplest solution, an enum class ComponentType

enum class ComponentType 
{
    Wire = 0, And = 1, Or = 2 
};

class UI
{

    ComponentType selectedComponentType; 
};

// Later in code

switch ( UI->selectedComponentType )
{
    case ComponentType::Wire:
        AddComponentAction<Wire>>();
        break;

    case ComponentType::And2:
        AddComponentAction<And>>();
        break;

    default:
        break;
}

I don't like this solution. I want to believe there is another more elegant way than to basically store a (in my naive eyes) seemingly redundant representation for type data that already exists inside my code.

One idea was to use a std::any variable where I put an instance of whatever component is selected, which at least feels more elegant than defining types again as enums.

    std::any selectedComponentType = And();


    if (selectedComponentType.type() == typeid(Wire))
    {
            AddComponentAction<Wire>>();
    }

    if (selectedComponentType.type() == typeid(And))
    {
            AddComponentAction<And<2>>>();
    }

Another was to create a virtual method in Components (the base class), and implement it seperatly in all derived classes. Then store the selectedComponentType as a pointer to Component, then use dynamic dispatch on it. But influenced by one responsibility principle I don't think I want the components themselves to be responsible or involved in their own creations.

Must there not exist some design pattern that solves this problem? Factory design pattern? The creation of my components is already facilitated by (a slimmed down version of) Command Design Pattern with Actions creating and deleting components, would that mean that I should make:

ActionFactory *selectedComponentType = AddComponentActionFactory<Wire>()

And then dynamically dispatch it's virtual initializeAction() method to get desired effect?

My deeper problem is that I also use the enum ComponentType inside each component to dynamically handle different rendering behaviors, for example: Wire is a line with node points, while the AND component is just a sprite.

Factory design pattern would not help here,

Is the solution always to create a new layer of classes with similar hierarchy structures as the underlaying problem classes, like in Factory Design pattern, to finally at the end be able to use the language built-in dynamic dispatch?

Aucun commentaire:

Enregistrer un commentaire