-
November 12th, 2012, 03:51 PM
#1
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?
-
November 13th, 2012, 04:07 AM
#2
Re: application design
hm, 100 views - no replies: there has to be a general problem to my approach. What is it?
-
November 13th, 2012, 06:14 AM
#3
Re: application design
Originally Posted by tuli
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.
Originally Posted by tuli
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
-
November 13th, 2012, 10:42 AM
#4
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
-
November 14th, 2012, 08:13 AM
#5
Re: application design
Originally Posted by tuli
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
-
November 14th, 2012, 09:43 AM
#6
Re: application design
Originally Posted by tuli
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?
Originally Posted by tuli
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?
-
November 14th, 2012, 12:51 PM
#7
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
-
November 16th, 2012, 10:01 AM
#8
Re: application design
Originally Posted by tuli
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
-
November 18th, 2012, 03:45 PM
#9
Re: application design
Originally Posted by tuli
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.
-
November 27th, 2012, 03:47 AM
#10
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|