Click here to Skip to main content
15,885,546 members
Please Sign up or sign in to vote.
5.00/5 (2 votes)
See more:
I am writing a C++ application where i have an object model and a UI (as most applications do). For the model, i have a main object and a number of specialised subclasses. The UI has context menus and property dialogs that i want to be specific to each object type. The main object has a number of actions that are available in the menu, but the subclasses need to add menu items (actions). And similarly for the property dialog - it needs to display data specific to each subclass.

My question is what is a good way to design this?

I can put all the menu creation code in each class, so that the specialised classes override the function to give their own menus. Like this (pseudo-code):
class MainObject {
    virtual MenuList getMenus() {
        return Menu("do something"),
               Menu("do something else"),
               Menu("do a third thing"),
    }
};

class SpecialObjectA : public MainObject {
    virtual MenuList getMenus() {
        return MainObject::getMenus() + Menu("special menu A");
    }
};

class SpecialObjectB : public MainObject {
    virtual MenuList getMenus() {
        return MainObject::getMenus() + Menu("special menu B");
    }
};

But that seems like the model classes are doing too much. They shouldn't be responsible for creating and managing UI objects.

So maybe i could create a separate object hierarchy for creating the menus. Each class would be responsible for creating the menu for it's respective model object. Something like this:
class MainMenuController {
    MainObject* theObject;
    virtual MenuList getMenus() {
        return Menu("do something"),
               Menu("do something else"),
               Menu("do a third thing"),
    }
};

class SpecialMenuControllerA : public MainMenuController {
    SpecialObjectA* theObject;
    virtual MenuList getMenus() {
        return MainObject::getMenus() + Menu("special menu A");
    }
};

class SpecialMenuControllerB : public MainMenuController {
    SpecialObjectB* theObject;
    virtual MenuList getMenus() {
        return MainObject::getMenus() + Menu("special menu B");
    }
};


class MainObject {
    virtual MenuList getMenus() {
        return new MainMenuController()->getMenus();
    }
};

class SpecialObjectA : public MainObject {
    virtual MenuList getMenus() {
        return new SpecialMenuControllerA()->getMenus();
    }
};

class SpecialObjectB : public MainObject {
    virtual MenuList getMenus() {
        return new SpecialMenuControllerB()->getMenus();
    }
};

But then i'm not sure where the logic for performing each menu action should go. Since each action operates on the model object, those MenuController classes above would need to know what object the action is for.

I am using Qt, so i could use their powerful signals and slots mechanism to do this, but i'm not quite sure how.
Does anyone have an idea of what Object Oriented design patterns to use here? I can provide more detail if my problem is unclear.

thanks
Posted
Comments
Sergey Alexandrovich Kryukov 10-Jan-11 19:23pm    
You're posing very interesting problems (my vote of 5), which need some thinking...

1 solution

This is a topic of prolonged discussion. Basically, you started to think in right direction, but still far away from well balanced approach.

First, let me offer some criticism. You first goal should be isolation of UI from "business logics". You first options is worse, because all mixed together. You formulation of the problem itself actually misses important point: you describe menu items, which are by far less important than menu actions.

First thing to do: you need to introduce a notion of action which is abstracted from the UI controls use to invoke an action. The action be invoked from any UI element you may decide.

Your second approach looks a bit better, but it will not reach your goals. 1) still you're thinking about menu items only; this is inadequate level of abstraction; and related: 2) why UI object are aware of logical objects, not the other way around? Right, the menu items (or whatever triggers the actions) act on the logical object, so the UI class holds a reference to it. But as the state of you logical object changes, the set of valid operations changes. What triggers that change? You may need to equip some "properties" describing logical objects with side effect to trgger UI representation of the object, and -- importantly -- the states of the controls user to trigger action should be invalidated. In terms of you menu items, some of the items should be enabled/disables, others probably renamed, hidden, etc. Don't forget, at the same time the logical object should be agnostic to UI controls and perhaps actions. Also, is your application multi-threading? it makes a big difference.

This way, we're running into some self-referencing deadlock in the design, from the other hand, it should bring the idea of having some intermediate agent sitting between the UI and you logical objects, some "middleman".

Working people devised different schema used to tackle such problems. You can learn them by getting familiar with some design patterns.

Here are the patterns you probably need to understand:

Model-View-Controller (MVC)

Model View ViewModel (MVVM)

Model-View-Presenter

First two are considered as architectural patterns, the last one as a design pattern, derivative from MVC, where the role of "middleman" is performed by Application Controller.

The choice of best-fitting pattern for you projects really depends on the scale of the project, its goals and other detail. It really takes experience and critical thinking.
 
Share this answer
 
Comments
Espen Harlinn 11-Jan-11 11:04am    
5+ Good answer
XTAL256 11-Jan-11 17:10pm    
Hi SAKryukov, thanks for your answer.

I am aware of the MVC pattern, although i never fully understood it (i get that it separates logic and UI, but that's only a basic understanding). I will read those links in the hope of learning more about it.

I understand that my first option is not ideal, i mentioned it because it is the easiest way i can think of to do such a thing. Obviously my question was how to do it better.

The menu problem is complicated since it involves executing actions. I will focus my question more on the property dialog. This dialog shown properties of an object and i want to give it tabs which display properties specific to each object type. The dialog uses HTML to display the data in a table, and the code to build that table is currently being done in the UI class. But now that i want specifics for each subclass, where should this code go? Like the menu problem, the model classes shouldn't be responsible for creating data for the UI. But i need to utilise polymorphism so the dialog can be used for all model objects yet display specific data.
XTAL256 11-Jan-11 19:29pm    
Regarding MVC, my model is what i posted above (the MainObject classes) and the view (for the property dialog) would be the HTML window. But what would the controller be? That is the part of MVC that i don't understand.
Sergey Alexandrovich Kryukov 11-Jan-11 19:38pm    
XTAL256, I really, really appreciate your desire to develop fundamental approach to the problem and your refusal to apply fast-baked ad-hoc techniques. You're touching the architectural problems which are much deeper that they may seem at first. Despite of existing design patterns, building up the architecture like that merely needs considerable experience. From the other hand, there is absolutely nothing impossible in your project, probably nothing unique as well.

Unfortunately, our conversation quickly floats out of the scope of Quick Answers and enters the phase where working together on a deeper level would be more adequate. If you could offer something like consulting job, for example, it might work...
XTAL256 12-Jan-11 16:43pm    
Yeah, i wasn't sure if this was the right place to ask this. To be honest, i don't really like this "Question and Answers" format as there is often more to be said than just a simple "answer". Many questions i have seen here have lengthy discussions which often would help the person but are not classified as direct "answers".

Would it be better if i post this on the message boards?

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900