I have to model a store with all kinds of articles. The user has to be able to filter these articles by type, price, ... . The store would contain a list of Article objects.

I've been stuck on whether to implement the Article class with a type field or to subclass new articles from the Article class.

Biggest problem I see when implementing with inheritance is the filtering by type. I'm going to have to lookup which type my derived objects in the Article list are, which would either require that every derived class has a getType() function or I'd have to use reflection to get the class name and work with that, both of which kinda defeats the purpose of inheritance. To access the specific fields of each derived class, i'd first have to filter by type and then downcast all Article objects of the correct type to that type to be able to access their specific fields. I have no idea if this is considered a good design.

On the other hand, I had the idea to have the Article class have a type field and a Map to represent it's data. I would then have to ensure that the necessary (key, value) pairs are added to the map for each different type and maintain an ENUM for the fields of each different type. Article would become an incredibly flexible class this way so I'd have to make sure my factory method's for each type would ensure the right pairs are added to the info map depending on the type. It would also require more discipline from the coder using the Article class to only access the map keys that are defined for that particular type.

I could also just keep different derived objects in different lists in the shop, but then I'd have to add a list every time I'd add a new article which isn't good for maintainability.

Any extra arguments for any of the possibilities that could help me decide would be appreciated.

  • 3
    Do differnt "types" of articles have different behaviour? – Kasper van den Berg Oct 18 '15 at 11:58
  • No, only the fields per article are different, with some articles having fields in common. – user200703 Oct 18 '15 at 12:13

It's important to remember that you don't need to create classes for different objects because they're different objects, you need to do it for when THE WAY YOU INTERACT with those objects is different.

For example, you have a "pencil" and a "stapler" in your Article store. for the purposes of purveying a pencil or a stapler to a purchaser, there is absolutely no difference between them.

If you have a "stapler" and a "music file download" then you have two objects that YOU have to treat differently...one is physical inventory (perhaps) and the other is not. One requires shipping, one requires downloading.

Sometimes this is hard to tease apart. The appearance of different attributes on the object can seem to indicate a different class type, for example that stapler may be "color=red" and it makes no sense to have a download with "color=red".

Again, to sum up: defining classes in a system is all about the differentiation in how you will interact with them, not in how different those objects might be.

  • 2
    upvote - very well said. I wonder if Walmart, for example, sees everything is just a SKU. Beyond that there may be many fields to describe, classify, etc each SKU. – radarbob Oct 18 '15 at 23:57
  • So you're saying that inheritance just for the sake of adding extra info would be bad design if I wouldn't interact differently with these derived objects? – user200703 Oct 19 '15 at 12:46
  • Then what's the right class design for multiple objects which have some common fields and some uncommon? And users of these objects sometimes use their common fields and sometimes uncommon. – Mudit Jain Mar 24 '18 at 22:24
  • Mudit, the word "polymorphism." should come to mind. it might be that you have a base interface and maybe abstract base class, with implementing subclasses that extend to the differentiable features. Take for example, you have a base interface that defines the .sortAscending() method, which is abstract in the base class. The sortAscending() method is defined in the subclasses, depending on whether the item is sorted by size, by weight, by count, by color, by cost...calling code doesn't have to learn what the sort param is...it calls .sortAscending() and lets God sort it all out. – dwoz Mar 26 '18 at 2:56

Using a type filed is a code smell.

Using a map for the articles properties may give you too much flexibility. We should always strive for flexible designs; so too much flexibility, is that possible? Yes it is, as you point out now you will have to check at other places that the articles satisfy the requirements of their "article type" which might lead to scattering this functionality all over the system and also scatter the differences in behaviour of different article types all over the system.

intends to concentrate the type specific behaviour of classes in the class, when you choose to use type fields and maps of properties you will need to ensure that the constrains on the different types are enforced in some other well designed mechanism. Sometimes you might need that flexiblity.

Using the type field for filtering articles is not bad, you could even allow extend it by allowing articles to have multiple types so that users might have improved search functionality.

  • 2
    If there is a type field, you would put as much of the code that depends on the type field into the class, so whether you have a type field is an implementation detail that isn't noticed outside. Otherwise you may get into trouble. – gnasher729 Oct 18 '15 at 20:53
  • 1
    PS. If the alternatives are to have a typefield and check it, or to check which class an object belongs to, I'd prefer the typefield. If the user of the class must treat articles of type1 different than type2, I'd go with the type field. – gnasher729 Oct 18 '15 at 21:00
  • there are those that would argue that the constraints (and bounds) checking of "type" or "property" fields is something that argues for getters and setters...and that a validator on a setter is the right approach? – dwoz Mar 26 '18 at 2:46

Do you know all possible types at compile time? Is it possible that your code needs to handle types that you never heard of? In that case you cannot have a class for that type.

Do you have more categories than just "type" for which you would want to create a different class? You might end up with a lot of classes. Ever seen a car manufacturer claiming that you can buy 9 billion different variations of a car? You better not try to create a class for each variation.

Whether class or typefield is better depends on the situation. And there will be borderline cases where neither is much better than the other, and it's a matter of taste.

Your Answer
