CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 10 of 10
  1. #1
    Join Date
    Jun 2012
    Posts
    58

    application design

    Hi everyone,

    1)
    I have a larger project here. It mainly consists of one window and a set of classes. At runtime, the class instances have to know about each other, ie class instance A might somehow use the class instance B, with which it is associated. I have simply wrapped all classes in one "Instance" class, and have declared a global function, which returns a pointer to the "Instance" class and thus allows the classes to use each other.

    This works well as "Instance" is a singleton.

    Now, however, i want to launch two windows in my program and would thus need TWO instances of the "instance" class!
    The concept fails. (ok, it wasnt pretty anyways...)

    2)
    A lot of the classes from above are Storage classes, ie classes whose main task it is to store a set of values (or whatever). Internally, it of course uses vectors/maps/lists/... to store the content, however the interface it provides may be more advanced.

    FOr example: A story may consist of several Scenes. The storage class would store instances of the struct "Scene", while providing an interface to work with more abstract problems, like overlapping or overall coverage. This is just an example.





    What would be an alternative/better approach here?

  2. #2
    Join Date
    Jun 2012
    Posts
    58

    Re: application design

    hm, 100 views - no replies: there has to be a general problem to my approach. What is it?

  3. #3
    Join Date
    Jul 2005
    Location
    Netherlands
    Posts
    2,042

    Re: application design

    Quote Originally Posted by tuli View Post
    1)
    I have a larger project here. It mainly consists of one window and a set of classes. At runtime, the class instances have to know about each other, ie class instance A might somehow use the class instance B, with which it is associated. I have simply wrapped all classes in one "Instance" class, and have declared a global function, which returns a pointer to the "Instance" class and thus allows the classes to use each other.

    This works well as "Instance" is a singleton.

    Now, however, i want to launch two windows in my program and would thus need TWO instances of the "instance" class!
    The concept fails. (ok, it wasnt pretty anyways...)
    So, get rid of the singleton. Since you already have a facade, I don't see why you need a singleton anyway.
    Quote Originally Posted by tuli View Post
    2)
    A lot of the classes from above are Storage classes, ie classes whose main task it is to store a set of values (or whatever). Internally, it of course uses vectors/maps/lists/... to store the content, however the interface it provides may be more advanced.

    FOr example: A story may consist of several Scenes. The storage class would store instances of the struct "Scene", while providing an interface to work with more abstract problems, like overlapping or overall coverage. This is just an example.
    What's your question?
    Cheers, D Drmmr

    Please put [code][/code] tags around your code to preserve indentation and make it more readable.

    As long as man ascribes to himself what is merely a posibility, he will not work for the attainment of it. - P. D. Ouspensky

  4. #4
    Join Date
    Jun 2012
    Posts
    58

    Re: application design

    So, get rid of the singleton.
    But how?
    As i explained above, i need at least one global function to access the "instance" class instance. When i have two of them, i cant do that anymore.

    An alternative would be to pass an instance pointer to every class involved.

    I dont really see my facade here

  5. #5
    Join Date
    Jul 2005
    Location
    Netherlands
    Posts
    2,042

    Re: application design

    Quote Originally Posted by tuli View Post
    But how?
    As i explained above, i need at least one global function to access the "instance" class instance. When i have two of them, i cant do that anymore.

    An alternative would be to pass an instance pointer to every class involved.

    I dont really see my facade here
    Maybe I misread your OP. Are you saying you have something like this now?
    Code:
    class Instance
    {
        Instance();
        Instance(const Instance&) = delete;
    public:
        static Instance& Instance();
    
        A& GetA() { return a; }
        B& GetB() { return b; }
        // etc
    private:
        A a;
        B b;
    };
    
    class A
    {
        void NeedsB() {
            B& b = Instance::Instance().GetB();
            // do something with b
        }
    };
    
    // client code
    void foo()
    {
        Instance::Instance().GetA().NeedsB();
    }
    If that's the case, then you've fallen into the trap of the singleton, which is exactly why many people advice against using it. (I wouldn't recommend against using it, but caution is certainly advised... as always).

    What you can do is make the Instance class an actual Facade. This means that instead of it just holding some instances of A, B, etc. and providing accessors for them, you can provide member functions that can be called by client code. E.g.
    Code:
    void foo(Instance& inst)
    {
        inst.Call_NeedsB_On_A(); // You'll have to be more creative coming up with names. "Instance" is a horrible name too, as it doesn't convey any meaning.
    }
    The functions in your facade have access to the instances of A, B, etc. so they can simply forward the call to the appropriate instance and pass a reference to any other instance that's needed.
    Code:
    void Instance::Call_NeedsB_On_A()
    {
        a.NeedsB(b);
    }
    Depending on your class design, this may be a big operation, but that's what you get when you use singleton and later figure out you shouldn't have. At the same time, you may want to review the class design to see if you can reduce the dependencies between classes.
    Last edited by D_Drmmr; November 14th, 2012 at 08:16 AM.
    Cheers, D Drmmr

    Please put [code][/code] tags around your code to preserve indentation and make it more readable.

    As long as man ascribes to himself what is merely a posibility, he will not work for the attainment of it. - P. D. Ouspensky

  6. #6
    Join Date
    Jan 2010
    Posts
    1,133

    Re: application design

    Quote Originally Posted by tuli View Post
    1)
    I have a larger project here. It mainly consists of one window and a set of classes. At runtime, the class instances have to know about each other, ie class instance A might somehow use the class instance B, with which it is associated. I have simply wrapped all classes in one "Instance" class, and have declared a global function, which returns a pointer to the "Instance" class and thus allows the classes to use each other.
    There's something bothering me there: "I have simply wrapped all classes in one "Instance" class"...
    What are you saying - that all of your class instances are global objects?! If so - why in the world would you do that?
    If not, then, as D_Drmmr suggested, get rid of singleton, and study the Facade pattern more closely - it provides an interface a subsystem, so that client code can (indirectly) interact with many other objects of a subsystem, without actually "knowing" about all those other types. Another pattern that limits the amount of dependencies is the Mediator pattern, which similarly provides a centralized way for many objects to interact, while being blissfully unaware of all the classes involved. While those classes don't know about each other, the Mediator knows them all, and its main job is to receive some messages (calls/data) from one object, and then forward them to other objects (maybe translating those messages in the process), as is appropriate for the needs of the application.

    Could you show some code, or at least provide an UML class diagram (sketch) of your current design, so that we can have a better picture?

    Quote Originally Posted by tuli View Post
    2)
    A lot of the classes from above are Storage classes, ie classes whose main task it is to store a set of values (or whatever). Internally, it of course uses vectors/maps/lists/... to store the content, however the interface it provides may be more advanced.

    FOr example: A story may consist of several Scenes. The storage class would store instances of the struct "Scene", while providing an interface to work with more abstract problems, like overlapping or overall coverage. This is just an example.

    What would be an alternative/better approach here?
    Is this a different question or you're elaborating on (1)? If it is, I don't see what exactly you're asking either. Could you be more precise/descriptive?

  7. #7
    Join Date
    Jun 2012
    Posts
    58

    Re: application design

    hi, and thanks for the replies.
    Are you saying you have something like this now?
    yes, that`s pretty much it.
    I tried to describe what kind of classes i have in my "Instance" in 2).
    Basically, one "Instance" holds a couple of storage class instances (==> described in in post #1 under 2) ) and represents one full running Instance of the program.

    I havnt written the codebase all this applies to, nor am i planning on doing a lot of corrections/modifications, but tbh i wouldnt know how to do it better.


    I dont really see the benefit of the proposed "Facade", as "void foo(Instance& inst)" still needs the "instance" instance as an argument...so essentially it still is a global object.
    Or are you suggesting, that all classes involved are passed a pointer to "instance"?


    What are you saying - that all of your class instances are global objects?! If so - why in the world would you do that?
    yesno.
    All class instances are bundled int oa singel class - which essentially is a global object, yes.
    Why? - Well, i`m looking for alternatives

    As described in #1, part 2, i have these storage class(es) which are essentially global and static to one running instance of the program.

    I`ll present some code or class diagram tomorrow, but it`s really pretty much what D_Drmmr suggested above.

    thanks again,
    tuli

  8. #8
    Join Date
    Jul 2005
    Location
    Netherlands
    Posts
    2,042

    Re: application design

    Quote Originally Posted by tuli View Post
    I dont really see the benefit of the proposed "Facade", as "void foo(Instance& inst)" still needs the "instance" instance as an argument...so essentially it still is a global object.
    Or are you suggesting, that all classes involved are passed a pointer to "instance"?
    No, the facade must know about the classes it wraps, but not the other way round. The advantage of using facade is that you can hide the dependencies between several classes and provide a simpler interface (mostly, easier to use correctly). So, instead of all classes having to call the singleton to get some other class instance, the facade can pass that instance when it forwards some function call.
    Cheers, D Drmmr

    Please put [code][/code] tags around your code to preserve indentation and make it more readable.

    As long as man ascribes to himself what is merely a posibility, he will not work for the attainment of it. - P. D. Ouspensky

  9. #9
    Join Date
    Jan 2010
    Posts
    1,133

    Re: application design

    Quote Originally Posted by tuli View Post
    Why? - Well, i`m looking for alternatives
    You must think that's a pretty smart answer... But the icon couldn't be more out of place. When I asked "why", it wasn't a smugly, rhetorical question, I meant: what are the requirements for your app that made you think that having global objects is the best way to do it?

    No hard feelings though.
    I see your problem: you created a singleton utility class and referenced all the dependencies through it, so now even if you made your singleton a non-singleton, you have no way of referring to the separate instances.
    You're gonna have to change the code.


    Using D_Drmmr's example:
    Code:
    class A
    {
        void NeedsB() //<-------------------------------------------+
        {   //                                                      |
    //                                                              |    
    //  This is still a dependancy on B right here, --+             |
    //                                                |             |
    //                                                |             |
    //                                                |             |
            B& b = Instance::Instance().GetB(); //<---+             |
    //                                                              |        
    //                                                              |
    //  Why not move it here  --------------------------------------+
    //  or even here ----+
        }  //            |
    //                   |
    //  <----------------+
    };
    Why didn't you, for example, pass the B object as a parameter? Is there a need to hide these dependencies from client code, or to limit the types of objects that can be interacted with?
    If so, you could have just prevented the user to construct those objects, and force all client code to rely on a factory-like class, so that all these instances can be constructed in a controlled manner.

    Regarding the facade approach:
    Code:
    void foo(Instance& inst)
    {
        inst.Call_NeedsB_On_A();
    }
    The code does not demonstrate how the objects within the system interact, but how client code (external to the system) would use the system - it would do so through the facade object, which represents the system as a whole, and provides methods for various functionalities of the system, here represented by the awkwardly named Call_NeedsB_On_A() function. So, client code would make a call to this function, which abstracts away the exact way of how the system completes the request; inside the facade object, which maintains references to all parts of the system, and defines the high-level interaction rules, the proper connections are established, proper functions are called on the proper objects, etc. Which is what this code snippet demonstrates:


    Code:
    void Instance::Call_NeedsB_On_A()
    {
        a.NeedsB(b);
    }
    Last edited by TheGreatCthulhu; November 18th, 2012 at 03:48 PM.

  10. #10
    Join Date
    Jun 2012
    Posts
    58

    Re: application design

    You must think that's a pretty smart answer
    Actually, i though i was admitting my failure to get it right in the first place...maybe that line should have been

    Why? - Well, i`m looking for alternatives now
    Thanks for the answer, though, i am in the middle of restructuring all this right now.

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