I have a number of types that all relate to each other in terms of them being 'derived' from one another. I'd need a way to do is
relationships, which made me initially think of classes, but I realized that other than the is
relationships, there would be no reason to use classes as each 'type' of data function the exact same way. I'd also thought of enums, but since there is no way to extend or inherit from enums it was a poor choice.
For context (this being my specific example): I have a number of different kinds of resources that all are 'types' so that they can be used in conjunction with an int to denote how much of that resource is available. I have several different kinds of these resources, such as foods, metals, building materials etc. Within the food category would be something like wheat or corn; under metals would be copper, iron, gold etc. Since all of these are still just 'resources' and have no actual functionality other than typing, it seems pointless to use classes and OO inheritance.
How would I implement this kind of data type without resorting to using classes?
-
A class that contains an enum member?Oded– Oded03/07/2014 14:09:16Commented Mar 7, 2014 at 14:09
-
Using classes to model type differences is often a good idea even when the set of fields is structurally equivalent. Why don't you want to use classes? Are you afraid of slowness?Kilian Foth– Kilian Foth03/07/2014 14:09:26Commented Mar 7, 2014 at 14:09
-
@KilianFoth Slowness isn't really an issue here, but if possible I'd like to keep memory usage down. It just seems rather pointless to have classes that all inherit from one another without actually adding on if there's another way to do it.PixelArtDragon– PixelArtDragon03/07/2014 14:12:10Commented Mar 7, 2014 at 14:12
-
I suppose the root of the issue is: Does it make sense to inherit from a class when you're not adding any functionality, and what's an alternative to this?Phil– Phil03/07/2014 14:16:36Commented Mar 7, 2014 at 14:16
2 Answers 2
If there are no functions to inherit, composition of structs may be more favorable than class inheritance. The concept of "composition over inheritance" may apply here, see:
Popular SO Answer to this issue
Although the above examples use classes, an alternative implementation could use structs:
-
If I'm understanding this correctly, what I could do is have each of the different instances of the one class have 'parent' instances, and to check the relationships I'd just need to compare the objects and their 'parent'?PixelArtDragon– PixelArtDragon03/07/2014 14:21:42Commented Mar 7, 2014 at 14:21
What you described is very much possible without checking is
relationships.
An object oriented design should rely on interfaces, not implementations. That means, code like this:
if (o is Derived1)
{
do_something_with_derived1(o);
}
else if (o is Derived2)
{
do_something_with_derived2(o);
}
Should be turned into
o.do_something_virtual(context);
Essentially, you move the responsibility of "doing something" from the caller to the callee. The caller only triggers this action. The callee knows its own type and can act accordingly. If there is any context on the calling site that you would use in the operation, you pass that as a parameter.
The key here is the virtual method, which allows for a dynamic dispatch. This removes the strong dependency to each implementation and "type checking" boilerplate on the calling site. The calling site can even call future implementations.
Another possible approach is a data driven design. Entity Component systems are a flexible solution that can be used to avoid complicated class hierarchies when each base class would only add a little bit of functionality (in your example: the kind and amount of resource).
-
The whole point of this is that there are no different functionalities; each type functions exactly the same, but need still to have a kind of hierarchy. The amount of the resource isn't actually stored within the classPixelArtDragon– PixelArtDragon03/07/2014 14:28:41Commented Mar 7, 2014 at 14:28
-
1@Garan there is actually new/different functionality, but misplaced in the calling site. You would write class-specific code outside the class, which is an antipattern. What I'm suggesting is the object oriented way of designing it.Tamás Szelei– Tamás Szelei03/07/2014 14:39:08Commented Mar 7, 2014 at 14:39
-
@Garan The point of the answer is "Eliminate your need for
is
relationships by refactoring your design a bit." If you eliminate your need foris
relationships, then type hierarchy becomes much less necessary.Phil– Phil03/07/2014 14:39:14Commented Mar 7, 2014 at 14:39 -
As for the amount being stored outside the class: you could pass that as a parameter, but maybe it would make sense to store in the class? Without knowing your requirements in more detail, it's hard to tell.Tamás Szelei– Tamás Szelei03/07/2014 14:40:12Commented Mar 7, 2014 at 14:40
-
@TamásSzelei The thing is, in a lot of cases the actual amount isn't necessary or even applicable to the situation. And while I could store the amount, it doesn't solve the very fundamental question of having an inheritance structure where new code isn't added.PixelArtDragon– PixelArtDragon03/08/2014 18:31:11Commented Mar 8, 2014 at 18:31