1

I'm reading a book that explain that it is a good thing that classes have a single responsibility, that is, that they do a single thing.

I can understand how to implement this in some cases I personally faced: - I needed an array of 6 countries returned to the model, so it can use it in the views... So I designed a class to do just that and only that. The class contained a few functions, each with a single task.

But what if I need in a game, a class "monster" that is responsible for the "monster" entity in the game. The monster can "attack", "hide" and "sleep".

That's 3 responsibilities, isn't it ? Then in this case, how to organize that monster class while still respecting the single responsibility principle ? I don't get it.

gnat
  • 21,442
  • 29
  • 112
  • 288
Robert Brax
  • 231
  • 1
  • 5
  • you shouldn't take simplistic statements in books too seriously... – AK_ Mar 06 '15 at 15:21
  • 4
    ["A class should have only one reason to change"](http://programmers.stackexchange.com/a/220292/31260) – gnat Mar 06 '15 at 15:24
  • If that were the case, a class would never have more than one method. Assuming having multiple methods that do the exact thing is an even worse idea. – JeffO Mar 06 '15 at 16:17
  • see also: [Clarify the Single Responsibility Principle](http://programmers.stackexchange.com/questions/17100/clarify-the-single-responsibility-principle) – gnat Mar 06 '15 at 17:10

2 Answers2

1

You need to consider how we use the word responsibility. If you are responsible for a child, that is a single responsibility. We all know there are many tasks you'll have to perform to maintain that responsibility.

So for your example of a Monster Class. You would only have functionality and data that pertains to the Monster. A monster has health and once the monster dies, the health value is gone from the individual monster, but could be recorded in some history. If you put the history in the monster class, you would lose it. If the monster was carrying a club, that would be a separate object that was possessed by the Monster, but upon the monster's death, the club would now be without an owner in some place another object could obtain possession. There's no law that says you have to do this, but if that was something you wanted to happen in your game, you'd have to figure out a way to maintain objects possessed by people but can still be available when the possession is lost. The monster can't take it with him.

So try to think in the perspective of what behaviors you want. If you find you're making changes to the monster because you want to change the club, you are getting out of the responsibility of the Monster class managing a monster character.

JeffO
  • 36,816
  • 2
  • 57
  • 124
1

Single Responsibility Principle means a class should only have a single "responsibility." This does not mean one "action" or one "attribute" however.

If I were to write down a list of what a monster in a game might need to do, I may come up with a list such as this one:

  • Monsters have attributes such as health and attack power. These attributes may change as the monster takes damage, or perhaps it can pick up a different weapon.
  • Monsters have an AI that governs its actions and differentiate dumb little monsters with tougher, smarter monsters.
  • Monsters need to be displayed on the screen somehow.

There are multiple responsibilities here. Clearly, "having health" and "having attack power" are not different responsibilities: they are both attributes that define what a monster is and how tough it is compared to other monsters.

The AI might be different responsibility. Perhaps a game has 200 types of monsters, and 10 different AIs. Different types of monsters might be grouped and act similarly: the AI does not need to be recoded each time, it can be shared. How the monster acts might be a responsibility of the AI, not the monster itself! For example, in the Diablo series of games, the Fallen (cowardly little imps) all act pretty much the same despite having slightly different appearances and different toughness.

Displaying a monster on the screen is a great application for an adapter object that has its own single responsibility: figuring out, for a given monster; where it is located, what state it is in (swinging its weapon, running, standing), and generally how it should look on screen.

In this example we might have a core monster object describing the current state of the monster, a pluggable AI that governs its actions, and an adapter object that knows the current visual state of the monster and can produce its graphical state to the graphics subsystem for display on screen.


Note that this analysis does not dig down to the level of individual functions or methods. I analyzed this at a higher level than that: getting bogged down in the nuts and bolts of the implementation is a bad idea when defining object responsibilities. Once those responsibilities are defined and you move on to the low level implementation details, of course you need to write the attributes and functions to support those responsibilities.

  • Thanks all for the great answers. So in you case where you have the 3 objects that govern the monster: state, AI, visual, would you put them each in their own "model" file, as I guess they should remain modular, and might be used by other class than monster (AI and Visual could be used on a class "Friendly NPC") ? – Robert Brax Mar 07 '15 at 12:42
  • Each would be its own separate class, and assembled together at runtime. Furthermore, and this was not in the question so I did not address it here, a monster would really be a type of "actor." Graphics adapters and AI would likely be compatible with that actor interface, not monsters specifically. –  Mar 07 '15 at 15:36
  • I would also like to point out that there may be additional responsibilities beyond the three I identified. This was a quick exercise to demonstrate how to split responsibilities and what their scope is. I was not trying to make a definitive list. –  Mar 07 '15 at 15:38