Let's say I'm using the mvc pattern to make a simple game in c++ and have a world object whose lifetime is managed by a controller class. This feels clearly like a composition, but what if, say a game logic class needs a permanent reference to the same world as well, or environments to this world (who is owned by the world) needs references to it, are these just regular associations or should I make all shared aggregations?
What makes me confused is that composition is defined as 'unshared'. But does this mean not shared with any other relationship, or only not shared with other aggregations and compositions. Also, how is shared aggregation typically implementet in c++? I mean, someone must manage the lifetime. Now we can use shared_ptr, but without them are everything shared just created in main and passed (and destroyd) from there? Which leads me to wonder; is it wrong to model the controller in a class diagram, should only the model part be modelled?
As another example of my main question (are composites allowed to be shared with any other kind of relation in a uml class diagram) e.g. can a wheel on a car be shared with other objects? If the engine needs a permanent reference, how should it be modelled? A simple association?
Yes, it is possible and one of the best example is that of a pool (the struture, not the one with water...). In a pool, the pool manager has a composition relationship with all the elements. The pool manager manages the allocation of elements to "users" as required. The users are now sharing these agregate elements.
It is important to note that the pool manager is the owner of the pool elements and is, therefore, responsible for their creation and destruction (as required to maintain the pool within prescribed limits) and needs to keep track of their allocation. The pool elements can also only have one owner. The pool's user can only borrow and return an element in this scenario.
In your scenario, I would suspect you can use either aggregations or just a simple association, keeping in mind that the owner of the object (the one with the composition) can destroy it...
Taking your car-part of the question, if you mean if it is legal to use both white and black diamonds in the same picture like in this one..
..then I think it is perfectly valid and doable.
In my understanding the black diamonds just represent the "ownership", saying who is responsible for releasing memory and chaining the calls to destructors and invalidating the other weak pointers (those coming from lines with white diamonds and lines without diamonds)
Another picture where both diamonds co-exist at the same time can be found at Kirill Fakhroutdinov's site under..
EDIT: after #gwag comment
http://www.uml-diagrams.org/library-domain-uml-class-diagram-example.html (see the Library class)
..http://www.uml-diagrams.org/dicom-real-world-uml-class-diagram-example.html (see the Visit class)
Your main question ("are composites allowed to be shared with any other kind of relation in a uml class diagram") is not very well expressed. You probably refer to components and not to composites. Indeed, a wheel, as a part/component of a car, cannot be shared with other cars (at the same time), while an employee, as a part of a company or team, can be shared with several other companies or teams..
But this non-shareability concerns only the two classes involved in the composition relationship (Car and Wheel, Company and Employee). And it does not restrict component objects to participate in other relationships instantiating other associations.
Related
I am designing a game engine in c++. I am currently working on categorizing the different entities in the game. My base class is SpriteObject that two classes MovableObject and FixedObject inherit from. Now if i for example create an instance of a MovableObject and want to add it to a Vector of Sprite and a Vector of MovableObject i just do:
Vector<Sprite*> sprites;
Vector<MovableObject*> movableObjects;
MovableObject* movingObject = new MovableObject();
sprites.push_back(movingObject);
movableObjects.push_back(movingObject);
But as the different categories and entities grow the code will get large (and it would get tiresome to add every entity to every vector that it belongs to). How do i automatically add an object to the vector that it belongs to when it is created?
EDIT 1: I think i just came up with a solution, what if i just make a global static class Entities that holds all the vector of entities in the scene. Every entity could have access to this class and when a entity is created it just adds a pointer version of itself to the corresponding vector(s) in that global class.
EDIT 2: But i forgot that my solution requires me to still manually add every entity to its matching vector. I just split the work among the different entities.
This is a nice problem.
I think that I would implement it like this: There will be an addToVector() method in Sprite class, and each derived class will override it to add itself to the corresponding vector.
I would suggest a different approach. But before I start I would like to note one thing with your current design.
I would hide the creation of those objects behind a facade. Call it a scene or whatever. Using new manually is bad from a couple of perspectives. First of all if you decide you want to change the scheme on how you allocate/construct your objects you have to change it everywhere in the code. If you have a lets say a factory like Scene you just change the implementation and the calls to scene->CreateObject<Sprite>() will remain the same everywhere else. This might get important once you start adding stuff like custom memory allocation schemes, object pools etc and at some point you will if you will start to grow your engine. Even if this is just an excercise and a for fun project we all want to do this like its actually done, right ;) ?
Now going back to the core - dont abuse inheritance.
MovableObject is not a Sprite. Static Object is not a sprite either. They are that, movable and static elements.
A sprite can be movable or static, so it has a behavior of a dynamic or static element.
Use composition instead. Make a Sprite accepting behavior, or better a list of behaviors. In fact the Sprite itself is just a behavior on a Game object too, it just controls the way it is presented to the user.
What if you had an object that can be attached multiple behaviors like the fact it is a dynamic one, it has a sprite presence on the scene and even more is a sound emitter!
If you add those behaviors to the object you have to create them first. They can, when constructed, decide to which list they should subscribe to.
This is all metaphors for actually a well known system, that is proven to work well and is actually used in most game engines nowadays. Its a Entity Component System.
You object with behaviors are Entities, Components are those Behaviors and each of them is controlled by one system that knows the component and knows how to update/handle them.
Objects in the scene are merely a set of components attached to them that act upon them.
I am designing a system, I have not yet implemented first I am just diagraming it and then will code it, I want to ask one simple question:
What to do when we are using both inheritance and composition at the same time?
For example, in a hotel, there are 2 kinds of room standard room and Twin room let us say. For this I can use inheritance concept and these 2 kinds of rooms will be derived class but i can also use composition and will make seperate class for standard and twin room, then will use this is my hotel class.
What should I do?
This question is kinda vague and there are many details missing, yet I'll share some ideas...
First thing: while working on design of your application, what matters the most are the requirements.
You need to try to identify entities that will have some meaning in your system first. Let's say you know that there will be Hotel and Room. Note, that this relation is a composition already, mainly because:
room can be part of only 1 hotel, it is not shared among multiple hotels
once the hotel is destroyed, so are all rooms in it
in C++, composition usually means "by value", i.e. class Hotel could have Room room; that would be an object with automatic storage duration with its lifetime tied to the lifetime of instance of Hotel, with multiple rooms you could just put them to the vector yielding the same relationship:
class Room { ... };
class Hotel {
public:
std::vector<Room> rooms;
};
(By the way, an aggregation would be most likely represented by a pointer or reference). This is another good example of composition:
If you know that there will be different kinds of rooms, first questions should be: will these objects have different behaviour? will my system treat them in different way? ...maybe you don't need to go for finer granularity than Room and everything that a concrete room will be specific with will be expressed with its attributes - size, number of beds, maybe dozens of boolean "has" flags ("has aircon", "has TV", "has microwave", ...), maybe all of its properties can be expressed with simple "type", values of which you would put into the enum.
I the case you site, I would have a room_type property on the room class, and I would set the type of the room_type property to an enumerated type with possible values of STANDARD and TWIN.
As long as there are not significant behavioral differences depending upon this type field, I would keep it simple.
If there are complicated behaviors, like predicting clean up based upon number of beds, changing pricing, and so on, I would use an abstract base class CRoom, and inherit CStdRoom and CTwinRoom from that, possibly setting a constant num_of_beds property in the class constructors.
You shouldn't use language inheritance to model business requirement inheritance. It just makes it too hard to modify or extend the business model. Language inheritance is for implementing features of your model, not the model itself.
Instead, derive all your objects from 'business object' or similar, to encapsulate common internal behaviour such as serialisation. Your classes can have types and you can use typeinfo, or you can use an explicit type field. Either way links between objects, whether inheritance-like or composition-like should be pointers (or index id fields) and collections (of pointers or index ids). [Your code snippet is fine, but pointers complicate memory management which integer ids avoid.]
Complicated behaviours should belong to other classes such as the Pricing, Cleaning, etc. There are other patterns to use in setting the relationships between business objects and business actions, but again avoid crystallising them using language features. You will regret it, if the system grows or changes even a bit.
Just a heads up, I have received little formal education on this type of design theory, so bear with me if I'm ignorant of some concepts. All of my reasoning comes from a background in C++. I am working on a component based system for use in a game engine, and this is the structure I have come up with.
There are components, which are just data.
There are nodes, which allow access to that data.
There are systems, which operate on nodes only.
There are Entities, which contain these nodes, components, systems, and other entities.
Pretty straightforward, but let's just focus on the components and nodes, which I have a pretty strict set of guidelines for.
a node can provide access to a collection of components within an entity
a node is dependent upon the existence of all its underlying components
a component can exist independent of any node pointing to it.
a system can only have access and act upon nodes
Now any of these nodes and components can be destroyed at any time. I've implemented this for nodes by using a set of intrusive lists to maintain a non-ownership method of iterating across nodes, and then they automatically remove themselves from the list upon their destruction. But now I have a question revolving about the components. On destruction of some component, all nodes must also be destroyed who were dependent upon that component. Normally, the simple fix to an object needing to be destroyed when another is destroyed is ownership, where you simply place the node within the component or dynamically destroy it within that components destructor, but nodes here can reference multiple different components. When an object has multiple owners, normally a ref counting solution like a smart pointer gives ownership to all those objects and is destroyed when all owners are destroyed, but that isn't the case this time. My big question, what do I do in terms of ownership when I have one object that can only exist when all its dependencies exist, and upon the destruction of any dependency, results in the destruction of that dependent object.
example:
Red are components needed for the existence of the second node
What it looks like after either component it depends on is destroyed
Obviously, there are multiple unclean solutions with weak pointers, manual deletions, and lots of checks for an objects existence, but like all issues, I'm wondering if this can be safely achieved by design alone. Again, if this is a very simple or well known concept, please just point me in the right direction.
#Jorgen G Valley - All of the objects are indeed owned by the entity, in that all objects are destroyed on destruction of the containing entity, but nodes, components, systems, and entities should be able to be added or removed at any time dynamically. Here is an example. Start with the world entity, which contains an entity which is one mesh and two vectors. The two vectors are updated independently, but let's say you want to parent them together, you would simply add a node, specify one vector as the parent, and any number of vectors as children. The addition of the node to the entity places it in a non-owning list, allowing the previously existant "Parent" system to iterate through all "Parent" nodes and perform functionality on each parent node. Unparenting the object involves just deleting the node, but then the vector and mesh should still exist. Let's say you want to destroy just that vector and hold onto the mesh for use in another model, than the destruction of that vector should also destroy the parent node, because it no longer references a valid vector.
Here are some visuals:
here is an example of the case above. here
now here is an example of removing the parent node. here
notice that the component stays around because it could be used in other nodes, like in this example, where the render node is using it. The destruction of the node closed the gap in the intrusive list used by the parent system, meaning the parent system only manages whatever other entities have parent nodes.
now here is an example of removing the vector component. here
In this case, all nodes dependent upon that vector must be removed as well, including the parent and render node. There destruction closes the gaps in those respective intrusive lists, and the systems continue on there way. Hopefully this helps illustrate the design i'm trying to achieve.
I think you are complicating things a bit more than you need. You say that nodes and components can be destroyed at any time. Is this really true?
In your text you describe the entity as the owner since you say it contains the components, nodes and systems.
My approach to this would be that a component would only be destroyed when the entity owning it is destroyed. This means that the node, component and system doesn't need to bother about destruction. It is done by the owning object, the entity.
EDIT: If you have situations where the component, node or system can be destroyed without the overlying entity to be destroyed I am intrigued to hear an example. It's a really interesting problem in itself. :)
I am having some issues designing the memory management for an Entity-Component system and am having some issues coming up with the detail of the design. Here is what I am trying to do (note that all of these classes except Entity are actually virtual, so will have many different specific implementations):
The Program class will have a container of Entity's. The Program will loop through the Entity's and call update on each of them. It will also have a few SubSystem's, which it will also update on each loop through.
Each Entity will contain two types of Component's. All of them will be owned by a unique_ptr inside the Entity since their lifetime is directly tied to the entity. One type, UpdateableComponent, will be updated when the Entity.update() method is called. The second type SubSystemComponent will be updated from within their respective SubSystem.
Now here are my two problems. The first is that some of the Component's will control the lifetime of their parent Entity. My current idea for this is that Component will be able to call a function parent.die() which would change an internal flag inside Entity. Then after Program finishes looping through its updates, it loops through a second time and removes each Entity which was marked for deletion during the last update. I don't know if this is an efficient or smart way to go about it, although it should avoid the problem of an Entity dieing while its Component's are still updating.
The second issue is that I am not sure how to reference SubSystemComponent's from within SubSystem. Since they are refered to by a unique_ptr from inside Entity, I can't use a shared_ptr or a weak_ptr, and a standard pointer would end up dangling when the Entity owning a component dies. I could switch to a shared_ptr inside the Entity for these, then use a weak_ptr in the SubSystem's, however I would prefer to not do this because the whole point is that Entity completely owns its Component's.
So 2 things:
Can my first idea be improved upon in a meaningful way?
Is there an easy way to implement a weak_ptr sort of functionality with unique_ptr, or should I just switch to shared_ptr and just make sure to not create more than one shared_ptr to the SubSystemComponent's
Can my first idea be improved upon in a meaningful way?
Hard to say without knowing more about the nature of the work being undertaken. For example, you haven't said anything about your use of threads, but it seems your design gives equal priority to all the possible updates by cycling through things in a set sequence. For some things where low latency is important, or there's some useful prioritorisation that would ideally be done, a looping sequence like that isn't good, while other times it's ideal.
There are other ways to coordinate the Component-driven removal of Entities from the Program:
return codes could bubble up to the loop over entities, triggering an erase from the container of Entities,
an Observer pattern or lambda/std::function could allow the Program to specify cleanup behaviour.
Is there an easy way to implement a weak_ptr sort of functionality with unique_ptr,
No.
or should I just switch to shared_ptr and just make sure to not create more than one shared_ptr to the SubSystemComponent's
It sounds like a reasonable fit. You could even wrap a shared_ptr in a non-copyable class to avoid accidental mistakes.
Alternatively - as for Entity destruction above - you could coordinate the linkage between SubSystem and SubSystemComponent using events, so the SubSystemComponent destructor calls back to the SubSystem. An Observer pattern is one way to do this, a SubSystemComponent-side std::function fed a lambda is even more flexible. Either way, the Subsystem removes the SubSystemComponent from its records.
In my project I have a series of classes where their instances are manged by some manager class, for specific reasons.
Examples would be:
CSound - Abstracts a single sound
CSoundManager - Friend of CSound,
provides factory methods for creating
CSound instances, mixes active sounds
together
Also: CFont, CFontManager (for font access per-name), CSprite, CSpriteManager (for drawing each frame), and so on.
Here my first questions already:
Is what I'm doing a specific named design-pattern?
Is it in most cases, for whatever reason, a bad idea? If yes, why?
Then, I have asked myself:
How should the objects be created and destroyed? Should I permit creating them on the stack or directly with new, or only by the methods of the corresponding manager class?
(also for destruction: delete myFont; versus. FontManager.DestroyFont( myFont );)
Sounds like you may be violating the The Single Responsibility Principle (SRP) principle.
Is the CSoundManager class responsible for creating and managing the lifetime of CSound objects, or is it in charge of mixing active sounds together? Names can tell you much, and "Manager" can be understood in too many ways...
Generally, if you want these Manager classes to handle the lifetimes of your objects, then they should most likely be the only way to instantiate these objects (i.e. private ctors in the objects). See the Factory Design Pattern, although your implementation is a bit different.
If you do this, then the client code should never call new or delete. Manually calling delete is bug-prone, and should be avoided using idioms such as RAII. In this particular case, the Manager class should manage the lifetime of objects, and therefore delete will never appear in client code.
Looks like you are using some form of Factory design pattern. Not sure what makes you feel its a bad idea.
If you are treating Manager as container of the objects then it would control the life cycle of these objects. However if your objects need to live beyond the life of Manager then you would create them with new and Manager may not be responsible for destruction.
Generally what you're implementing is a Factory Method Pattern wherein an object allocates another object. However, you are not reaping the benefits of a Factory class as you're directly tying the allocated type to the factory as opposed to allowing the factory to manage all the internals abstractly. For instance, can you do this from any file, or just the factory for that resource type (CSoundManager): new CSound();
If so, you're missing the point and you basically just have a Singleton that allocates and manages an object. Consider abstracting your resource types. If CSound and CFont derived from IResource, you could have a CResourceManager that would just take an enum or some sort of identifier for that type and reduce coupling and dependencies in your codebase. Whenever you needed to use that object you could expose the type but more likely than not you could use an abstract manager (CResourceManager) to handle those objects using common interfaces (Update(), Create(), Destroy() etc...).
For your sound manager case, remember that sounds need only be loaded once and can be instanced with a unique state. In that right, have the resource manager manage the actual resource (CSound), and the sound manager (CSoundManager) maintain discrete instances (e.g. CSoundInstance) and manage mixing (via CSoundMixer). Specialize your classes in meaningful ways that manage complexity and reduce redundancy.
I used the sound manager as an example but this holds true for most io systems (graphics, input, physics).