CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 9 of 9
  1. #1
    Join Date
    Feb 2006
    Posts
    35

    Application framework design question

    In creating an application I tend to have a central object that acts as a main hub to control sub-object lifetimes and provide object services.

    Code:
    class ISaveLoad
    {
    public:
    virtual void save( IApp *pHub, char *fileName, char *pdata, uint32 size ) =0 { ... } int32 countFiles(char *folderName) { ... } ...
    }; class IApp { public:
    virtual ~IApp() {} virtual void startup()=0 {} virtual void shutdown()=0 {} ... ISaveLoad *m_pfileMgr;
    }; class SaveLoad : public ISaveLoad { public:
    void save( IApp *pHub, char *fileName, char *pdata, uint32 size ) { ISave::save(pHub,fileName,pdata); ... }
    }; class MyApp : public IApp { public:
    MyApp() : IApp() {
    m_pFileMgr = new SaveLoad();
    }
    static MyApp &getInstance() {
    if( !s_pInstance )
    s_pInstance = new MyApp();
    } virtual void startup() {
    IApp::startup(); ...
    } virtual void shutdown() { ... IApp::shutdown(); }
    private:
    static MyApp *s_pInstance;
    };

    Now the interface IApp will contain generic non-app specific objects like saving, loading, sound, screen res, registry access, etc, etc. Some of these objects will need to call on each other so will often need to know about base part of MyApp. They'll include IApp.h and need an IApp pointer. Some of them will get overridden by MyApp and contain low level generic elements, but also high level app specific elements.

    The application MyApp will contain app-specific code to layout menu screens and do actual work, etc. Again these objects will need to call on each other occasionally and more often the objects of the base. So they'll include MyApp.h sometimes and IApp.h often and need a MyApp/IApp pointer.

    To service the application's need for MyApp access I make MyApp a singleton and then any app-specific code can include the appropriate headers and call MyApp::getInstance(). The aim is to avoid that call where possible and instead favour using the base interface. The theory being that it's ok for app level code to use the services of the base and therefore become dependant on it as at the base level the code should all be generic. App level code becoming dependant on app level objects is not good as that starts increase coupling to non-generic objects.

    I'm not sure I've explained it very well, but it seems like there are two layers to an application: a generic base layer and an app specific higher layer. This happens even within a single object, some low level non-virtual parts, some virtual high level parts. Patterns emerge where the low level objects and object parts tend to couple with each other. Whereas the higher level objects and object parts tend to couple with the lower level. That kind of coupling seems i.e. low -> low and high -> low and it's only when high -> high occurs that you get a lot of problems. Obviously any coupling should be minimised, I'm just talking in general terms.

    Initially I found I was constantly passing MyApp pointers into the low level generic objects as they don't have access to the MyApp singleton so can't get at the hub. This seems wrong, extra paramteres on every function. At the base level I'd like to go IApp::getInstance() but I don't think that can be done simply.

    Here's one idea, but it worries me.

    Code:
    class IApp
    {
    public:
    IApp() {
    assert(!s_pBaseInstance); s_pBaseInstance = this;
    } static IApp &getBaseInstance() {
    assert(s_pBaseInstance); return s_pBaseInstance;
    }
    private:
    static IApp *s_pBaseInstance;
    };
    So now app level code can call MyApp::getInstance() if it needs to couple to other objects and low level generic code can call IApp::getInstance(). If I make sure low level generic code never calls MyApp then it never needs to know about MyApp or include any header files from that higher level.

    The obvious problem is if you had two Apps in the same execution each inheriting from IApp. That would be a disaster, but that should never happen - one execution == one app.

    Is there a better way of doing this or is this ok? Maybe this is all systematic of relying on inheritance and polymorphism, I know people are starting to say we should avoid inheritance all together and favour object composition instead. Maybe my whole approach is wrong

  2. #2
    Join Date
    Aug 2007
    Posts
    135

    Re: Application framework design question

    i understand that you have spent some time writing the above post.
    It would help if you let us know what you are trying to achieve (what is your overall goal - your application/program). What is the basic idea how you are trying to achieve. And from there you can go ahead and break your system down into objects.

    if you introduce code, without clearly defining your objective, you may not get the inputs that you desire. It always helps to let the other person know what you are trying to achieve, before continuing to how.

  3. #3
    Join Date
    Feb 2006
    Posts
    35

    Re: Application framework design question

    Sorry, I'm creating a 2d game development framework that supports multiple platforms (PC/Mac/Linux). Something that is generic enough to build multiple apps with for years to come. There's a lot of commercial middleware involved as well (rendering, sound, compression, gui) and this has a tendancy to come and go over time so the app needs protecting from it.


    I guess it's something most developers aspire to create in most development work - a stable framework to help speed up projects. It's strange though that I've never really seen it work in practice. In my experience (C++ only) most programmers have a grab bag of ~50 bits of "utility" code that genuinely get reused, but tend to get get hammered into shape on each project. So called commercial/osource frameworks or engines tend to be hard wired into specific platforms or libraries. This always seems a bit unsatisfactory and something more sophisticated should be possible.

    In the past I've always started out with such good intentions, but then inexperience and time pressure means the code base tips too far into entropy and I end up rewriting a lot of code on new projects or not feeling comfortable porting to new platforms. Over time I've noticed these patterns emerging (app specific objects, generic objects, objects with elements of both, the good and bad ways they couple together, the need for a central hub of services). I'm wondering if this is reasonable design, is it normal, is it a result of a reliance on inheritance and polymorphism, is there a better way?

    Re-reading this it sounds like I need a good book or two. I try to do a fair bit of reading, but most of the texts I've had seem to focus on lower level issues rather than this high level problem of creating a reliable, maintainable, reusable framework.

    Somewhat deep for a forum post I suppose

  4. #4
    Join Date
    May 2007
    Location
    Bangalore India
    Posts
    262

    Re: Application framework design question

    Quote Originally Posted by fezztah
    In creating an application I tend to have a central object that acts as a main hub to control sub-object lifetimes and provide object services.

    Code:
    class ISaveLoad
    {
    public:
    virtual void save( IApp *pHub, char *fileName, char *pdata, uint32 size ) =0 { ... } int32 countFiles(char *folderName) { ... } ...
    }; class IApp { public:
    virtual ~IApp() {} virtual void startup()=0 {} virtual void shutdown()=0 {} ... ISaveLoad *m_pfileMgr;
    }; class SaveLoad : public ISaveLoad { public:
    void save( IApp *pHub, char *fileName, char *pdata, uint32 size ) { ISave::save(pHub,fileName,pdata); ... }
    }; class MyApp : public IApp { public:
    MyApp() : IApp() {
    m_pFileMgr = new SaveLoad();
    }
    static MyApp &getInstance() {
    if( !s_pInstance )
    s_pInstance = new MyApp();
    } virtual void startup() {
    IApp::startup(); ...
    } virtual void shutdown() { ... IApp::shutdown(); }
    private:
    static MyApp *s_pInstance;
    };

    Now the interface IApp will contain generic non-app specific objects like saving, loading, sound, screen res, registry access, etc, etc. Some of these objects will need to call on each other so will often need to know about base part of MyApp. They'll include IApp.h and need an IApp pointer. Some of them will get overridden by MyApp and contain low level generic elements, but also high level app specific elements.

    The application MyApp will contain app-specific code to layout menu screens and do actual work, etc. Again these objects will need to call on each other occasionally and more often the objects of the base. So they'll include MyApp.h sometimes and IApp.h often and need a MyApp/IApp pointer.

    To service the application's need for MyApp access I make MyApp a singleton and then any app-specific code can include the appropriate headers and call MyApp::getInstance(). The aim is to avoid that call where possible and instead favour using the base interface. The theory being that it's ok for app level code to use the services of the base and therefore become dependant on it as at the base level the code should all be generic. App level code becoming dependant on app level objects is not good as that starts increase coupling to non-generic objects.

    I'm not sure I've explained it very well, but it seems like there are two layers to an application: a generic base layer and an app specific higher layer. This happens even within a single object, some low level non-virtual parts, some virtual high level parts. Patterns emerge where the low level objects and object parts tend to couple with each other. Whereas the higher level objects and object parts tend to couple with the lower level. That kind of coupling seems i.e. low -> low and high -> low and it's only when high -> high occurs that you get a lot of problems. Obviously any coupling should be minimised, I'm just talking in general terms.

    Initially I found I was constantly passing MyApp pointers into the low level generic objects as they don't have access to the MyApp singleton so can't get at the hub. This seems wrong, extra paramteres on every function. At the base level I'd like to go IApp::getInstance() but I don't think that can be done simply.

    Here's one idea, but it worries me.

    Code:
    class IApp
    {
    public:
    IApp() {
    assert(!s_pBaseInstance); s_pBaseInstance = this;
    } static IApp &getBaseInstance() {
    assert(s_pBaseInstance); return s_pBaseInstance;
    }
    private:
    static IApp *s_pBaseInstance;
    };
    So now app level code can call MyApp::getInstance() if it needs to couple to other objects and low level generic code can call IApp::getInstance(). If I make sure low level generic code never calls MyApp then it never needs to know about MyApp or include any header files from that higher level.

    The obvious problem is if you had two Apps in the same execution each inheriting from IApp. That would be a disaster, but that should never happen - one execution == one app.

    Is there a better way of doing this or is this ok? Maybe this is all systematic of relying on inheritance and polymorphism, I know people are starting to say we should avoid inheritance all together and favour object composition instead. Maybe my whole approach is wrong
    According to me make IAPP as singelton the way you have done..
    But dont make operator= as private. In fact overload operator= in your IApp class.

    Like the following.
    Code:
    class IApp
    {
      const IApp& operator=(const IApp& myapp)
      {
    	 single = &myapp;
      }
     static IApp* single;
    .....
    .....
    }
    Now instead of passing various MyApp object pointer to many methods of IApp you could do assigment.
    Code:
    IApp* pt = IApp::CreateInstance();
    MYApp1* myapp1= MYApp1::CreateInstance();
    MYApp2* myapp2= MYApp2::CreateInstance();
    pt = myapp1;
    pt->DOSomething();
    pt = myapp2;
    
    pt->DoSomething();
    virtual destructor and everything you have to take care of yourself..

    NB: Hope I understood your problem correctly.
    Dont forget to rate my post if you find it useful.

  5. #5
    Join Date
    Jun 2002
    Location
    Moscow, Russia.
    Posts
    2,176

    Re: Application framework design question

    Hi fezztah,

    So the main point of App instance is to store choices of implementations of various objects that may be needed from different points in the program. An App instance represents a configuration, where specific implementations of known interfaces are selected. If you intend to have this choice fixed for the process, it's OK to keep it a singleton. If you intend to run multiple configurations in the same process, you'll need to pass the correct instance of App along to its users, or to have any other indication of specific configuration with which that code needs to work. For example, if you have multiple threads, you can place configuration in correspondence with the thread, and request the thread class as needed, wrapped in helper access method that will look just like a singleton.

  6. #6
    Join Date
    Aug 2005
    Location
    LI, NY
    Posts
    576

    Re: Application framework design question

    Quote Originally Posted by code_carnage
    According to me make IAPP as singelton the way you have done..
    But dont make operator= as private. In fact overload operator= in your IApp class.

    [...]
    Not sure what you're getting at here. Any appearance of operator= in an ADT (let alone a singleton), that isn't an unimplemented private declaration (EDIT: or a protected implementation), strikes me as nonsense. It also isn't clear from your example where operator= is getting called.


    Concerning the OP: It seems like your concern is that if you have two app-specific singletons deriving from IApp, a run-time error will be generated, as opposed to a compile-time error. However, there are reasons not to fret over that fact:

    - It is highly unlikely that an application would try to create two app classes knowing that doing so is an error (I guess this is the main point you brought up).

    - The constructors of your app singletons will almost certainly be among the first things called in your program (otherwise they wouldn't really represent an application), possibly even before main is called. If more than one app is created, you'll know straight away, without having to worry that the error is lurking in some esoteric feature of your program.

    - The runtime error in question is an assertion failure. It is not undefined behavior, so you will know if the error occurred, and it will occur right away (see previous bullet).


    It also may be the case that a re-design is in order. From the information given, it is not clear why IApp is a necessary base class, and why it should provide the grab-bag of services you listed. Why not have a set of classes that relate to sound, others that relate to serialization, and so on? Why force the notion that an application is an object with a run() and onInit() method and whatever else, when the same is accomplished will a few function calls from main? Does it make you feel better about having global state in your application to put it all in a singleton?
    Last edited by Hermit; June 11th, 2008 at 08:05 PM.
    - Alon

  7. #7
    Join Date
    May 2007
    Posts
    811

    Re: Application framework design question

    If you are just looking for cross-platform framework, wxWidgets might be helpful. I have used it before for some of the games.

  8. #8
    Join Date
    Feb 2006
    Posts
    35

    Re: Application framework design question

    Quote Originally Posted by Hermit
    It also may be the case that a re-design is in order. From the information given, it is not clear why IApp is a necessary base class, and why it should provide the grab-bag of services you listed. Why not have a set of classes that relate to sound, others that relate to serialization, and so on? Why force the notion that an application is an object with a run() and onInit() method and whatever else, when the same is accomplished will a few function calls from main? Does it make you feel better about having global state in your application to put it all in a singleton?
    This is what I was wondering, is there a better way. What you're describing sounds like pulling all the service objects out of IApp and creating/destroying them in main. Maybe I'm not following you, but surely you'd still need a way for all your MyApp (high) level objects to get hold of them? So you'd presumably end up with them all as singletons? They'd all need to individually manage platform specific issues. What about objects that have generic and app specific elements which in my current system is handled by inheritance of virtual functions. As it stands now IApp gives a comforting order by collecting all the generic apsects, while MyApp collects all the app specific aspects. I'm not explaining that well, but what benefit does breaking objects out of a central App object give you?

  9. #9
    Join Date
    Feb 2006
    Posts
    35

    Re: Application framework design question

    Quote Originally Posted by STLDude
    If you are just looking for cross-platform framework, wxWidgets might be helpful. I have used it before for some of the games.
    I looked at that previously and used the file handling aspects of it in a small cross-platform patching program. It scared me though as it's a huge library. I like to feel I understand the design and function behind the code and I'm not sure how long it would take with something this big. From what I used (which wasn't much) it felt just like a toolkit of functions, it didn't seem to enforce or encourage a specific over arching application design. Maybe it does if you explore more of it.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured