   Design Pattern
  Hi all,Classically I developed applications with pairs of h/cpp files for various interfaces, e.g. graphics.h/cpp, network.h/cpp, etc, with various functions of each accessible from other modules simply by including the necessary header files.I understand that this is a sloppy method of programming (though I guess some C zealots might argue otherwise!). Nonetheless, lately I have started migrating my design patterns to a more comprehensive and structured C++ method of having one CApplication class which manages most of the other objects and interfaces for my game.The problem I am currently facing, is designing the relationships between various classes.For example:class CApplication{   CEventList Events;   CNetwork Net;   CDatabase DB;};What I was going to do is move the CEventList functionality/methods into CApplication, and handle the events inside CApplication::HandleEvents(), however how should each of the other classes (Events, DB) manage access to the CApplication::AddEvent() such that they can add their own events to the event queue?I can think up numerous ways around this (storing a CApplication pointer in various classes, keep functionality in the CEvents class and pass this as a pointer to anything which needs access to it, then process the events inside CApplication::HandleEvents(), and others ... what I am really looking for is the best (e.g. cleanest, most scholastic, most bragging rights, etc) method of handling this sort of fundamental application design.Thanks,   
class Whatever{public:  void InstallEvents( CApplication &app )  {    // install handlers  }}....class CApplication{public:  void InstallHandlers()  {    DB.InstallEvents( *this );    Net.InstallEvents( *this );  }}This is one way.Quote:for is the best Everything is a compromise. There is never "best", only "optimal". Optimal set of trade-offs to solve your problem.In your case, your original solution might have been optimal for your given application, even if it was "ugly".   ;Quote:Original post by DarkHorizonI understand that this is a sloppy method of programming (though I guess some C zealots might argue otherwise!).What you are describing is a perfectly valid procedural architecture. It has some advantages and disadvantages that object-oriented architectures don't have, but isn't "better" or "sloppier". It may be a bad fit for your needs, though.Quote:Nonetheless, lately I have started migrating my design patterns to a more comprehensive and structured C++ method of having one CApplication class which manages most of the other objects and interfaces for my game.I don't like where this is going—the dreaded 'god class', which is procedural programming posing as 'OO-ish' code. If you want to go with an object-oriented approach, you should do it correctly.Quote:what I am really looking for is the best (e.g. cleanest, most scholastic, most bragging rights, etc) method of handling this sort of fundamental application design.I can provide you with two simple metrics to determine whether your object-oriented design is 'correct' or not. The first metric is that every single bit of functionality should be reusable in another project:Good: Does the functionality correspond to a single module ? That is, can you just instantiate one class or call one function and get your effect, or do you have to go through hoops such as instantiating ten unrelated classes, initializing two globals, setting up a mutex, calling three preliminary functions and finally getting your result? In short, can you provide a twenty-line stand-alone source file demonstrating how to use that feature? This is the "to convert a file from BMP to PNG, you must create an OpenGL window" syndrome.Bad: Is the functionality only a small facet of a huge class ? That is, to perform a simple operation, you use a class or function which could also perform tens or hundreds of other moderately unrelated functionality. In short, do you have a clear 'one class, one responsibility' rule, or do you plug as many things as possible into one class? This is the "Determining if a point is in a rectangle is a member function of the MouseCursor class" syndrome.Bad: Does your class or function make assumptions about the rest of the program? Ideally, an object should only make assumptions about its constructor arguments, and a function only about its arguments. Also, make sure that you're not overspecifying things: if a function needs to update an object ('obj.update'), it should not require or even assume that the object also has a 'obj.render' function. This is the "You need to specify operator< for your objects to store them in my container" syndrome.The second metric is the absence of circular dependencies. If A needs B and B needs A, then either A and B are very strongly related (they provide almost the same functionality: container and iterator, mutually recursive tree traversal functions) or they shouldn't depend on each other. You can have A need B and B need C, where C can be a facade for A (or A', or A" etc), or (even better in many cases) have B need a facade for A and A need a facade for B, so that you may reuse either more easily.To discuss your particular problem, think in terms of objects instead of systems. Does the network need to know that there is an application? It doesn't need to. Neither does the database.   ;Quote:Original post by ToohrVykTo discuss your particular problem, think in terms of objects instead of systems. Does the network need to know that there is an application? It doesn't need to. Neither does the database.This is a bit of a stumbling block for me. I grant that any given component of an application should be functionable independently of the rest of the app. But then, in order to integrate everything into a cohesive program, they do need to talk to each other. I can come up with three solutions, none of which seem optimal:Have the App class keep pointers to each system, and then an object requests a pointer when it needs it.Have objects keep pointers to whatever they will need to talk to.Implementing some sort of message-passing system. What I don't get about this is how to create a set of valid messages without requiring more dependence.I feel like I'm not grokking some integral aspect of design :?   ;Quote:    * Have the App class keep pointers to each system, and then an object requests a pointer when it needs it.    * Have objects keep pointers to whatever they will need to talk to.    * Implementing some sort of message-passing system. What I don't get about this is how to create a set of valid messages without requiring more dependence.What exactly are your options?- Callback interfaces- Functors- Function pointers- Messages???Choose one.What does network need to know about application? Zero. Nada. Only a callback in the form of:void dataReceived( IPAddress &addr, Buffer &buffer );Application on the other hand will respond back:IPAddress destination( ... );Buffer buffer;buffer.writeInt( 17 );buffer.writeInt( 15 );network.send( destination, buffer );Now neither knows about either, and communication between the two is performed through common classes (address, buffer).And so on.As always, YMMV, there's alternate solutions, close coupling is sometimes desirable, hard-coding may be better, and so on ad infinitum.Ah, but how does network know the application settings. Singleton, right? Nope.When you create network object, you pass the settings to it:class Network{  Network( std::map< std::string, std::string> &properties )  {    targetAddress = properties["TargetAddress"];    targetPort = properties["TargetPort"];    fooBar = properties["FooBar"];  }}Application obtains these from elsewhere, settings module, configuration loader, boost::program_options, and then passes them on creation to all the sub-systems.Once again, Network has no clue who provides the settings. It only knows they'll come from somewhere. Application also doesn't care who receives the settings. It merely offers them.   ;Quote:Original post by yckxHave the App class keep pointers to each system, and then an object requests a pointer when it needs it.Have objects keep pointers to all systems they will need access to.Implementing some sort of message-passing system. What I don't get about this is how to create a set of valid messages without requiring more dependence.You're still thinking in terms of systems. If your program uses an array, do you think in terms of 'std::vector is the continuous storage system of my program' ? You probably don't, you just consider the vector to be yet another tool that your program uses to achieve a result. So, instead of thinking about your objects in terms of 'systems' (something which implies a hint of global uniqueness and existence), think about them in terms of tools used by other objects or functions to accomplish their own goals.In a game, objects and patterns generally fall into four categories: The 'entities'. These are individual objects which can be 'models' (they represent some kind of universal in-game block of data independent of graphics or sound), 'view' (they represent a visual or audio aspect of an in-game entity) or 'controller' (they aggregate a model and zero, one or more views, and sync them together).An important part of entities is that they're alone in the dark: their main purpose and focus is their internal state, they never take the initiative to reach out and manipulate something. Any interaction between an entity and something else is initiated by that something, which can call a method for immediate reaction, or provide a listener for delayed reaction. Entities are lonely black boxes. They react to your method calls, they never interact with the rest of the program (or know about its existence) ever.The 'manipulators'. These manipulate entities: they are the objects allowed to take the initiative and actually do stuff. For instance, rendering video 'view' entities, or testing for collisions beween 'model' entities, or even creating new entities and registering them with manipulators, is a manipulator's job (though that manipulator may do so in response to an entity's state change). Manipulators know about just enough to get their job done. They certainly can manipulate entities (though 'view' manipulators generally only know about 'view' entities and 'model' manipulators only about 'model' entities) as well as other manipulators which they need to get their job done (a manipulator which computes the physical interactions of a set of entities will probably have its own collision-detection manipulator, or perhaps optionally use an external one provided during construction).The game is a tree of manipulators which use other manipulators, which in turn use other manipulators. Each has a simple task (one sentence only) which is then accomplished in detail by the sub-manipulators.The 'glue'. These are all the bits and pieces which are neither entities nor manipulators, but which are necessary to make the two interact. They are typically the Adaptor, Facade, Listener, Visitor patterns used to emulate functional programming features and make manipulator-entity interaction more rich.Glue is generally extremely local, about as local as a class method. It generally serves to couple one given manipulator with one given entity, without either of these knowing about the details of the other (the manipulator sees a listener which is triggered when a certain condition is met, the entity sees a listener to be triggered when that condition is met). Glue represents the actual coupling between objects in the program.The 'tools'. These are the other mode of interaction and communication. Where glue is extremely specific and restricted to a single interaction, tools are designed to perform the same interaction in hundreds of unrelated places. A smart pointer, a container, a void callback are all examples of building blocks that will allow you to reuse something using them everywhere without having to pull along all the glue to make it work.Often, you will find that two objects interact by each asking for or providing a tool as part of their interface, and a glue object implementing that tool.;Quote:Original post by ToohrVykIn a game, objects and patterns generally fall into four categories:That's a really good breakdown, thanks ;) Now I just have to let my brain digest that info, and then go study the current and future state of my code.   ;  ToohrVyk:You say that entities are alone in the dark and doesn't initiate anything.Are they allowed to send messages, and in that case, to whom ?Can you expand a little more on the glue part? Perhaps give a few more examples.I would like to get a clearer view on what you place in this group.I find these kind of topics deadly interesting. It's hard to find any good info of structure and design of games so I appreciate anyones input and experience on this subject.   ;  I consider entities to be mute as well. Their job is working on their internal state, not acting on the external state. Entities hold a passive philosophy of 'I provide people with information about my state through a full interface, both immediate and delayed, and I let people alter my internal state without ever causing any external side-effect myself.' In this philosophy, listeners are not an external side-effect—they're used as a continuation mechanism on the manipulator side, which merely waits for the entity to 'return' some data before continuing execution.Thus, an entity never sends messages, it only responds to messages. Manipulators set up message systems so that an entity's reply may cascade into a message sent to another entity, but this is the manipulator's job, not the entity's.Entities are allowed to interact with each other in a limited way using glue. Say, for instance, that you want a missile to follow a spaceship. You first clean up this interaction: the followed spaceship doesn't have to know that it's being followed, and the missile doesn't need to know that it's following a spaceship, only that it's moving towards an object with position and velocity parameters. So, you represent the interaction by having the spaceship entity publish a 'movement' object (Adaptor pattern) which forwards the requests for position and velocity to the appropriate methods of the spaceship, and having the missile require a 'movement' object to follow. Should the followed object disappear (for instance, by dying) the 'movement' object becomes invalid.Actually communicating the adaptor from an object to the other is done by a manipulator, for instance one specialized in target finding: the missile is provided upon creation with a 'target list' object (Adaptor pattern again) which can be used for finding a target with certain properties among objects which are being handled by the manipulator. The target list provides access to 'movement' objects. So, the missile class looks like, in pseudocode:class missile(scanner t)  scanner targets = t  movement target = null  update:    if (target is valid) follow target    else  target = targets.find()    require next update in 10 msThis class can be plugged just about anywhere. It assumes nothing about what is being followed or how the targeting manipulator selects targets. It's a brutish 'follow the target' missile.   ;  Say I have a manipulator that I want to do something in reaction to some state change of a given (type of) entity. The entity shouldn't broadcast the event, because it is mute. Continually polling a collection of these entities seems expensive and inefficient; but implementing a callback system for entities seems to violate the guideline of mute entities, as well as functionality it shouldn't need to have.Is there another way, or am I seeing bugbears in one or more options where there are none?   