Classes and OOP

Started by
5 comments, last by Ravyne 9 years, 9 months ago

A general question.

When designing a program and separating the different elements into separate classes; at what point should a task be relegated to another class as opposed to making it merely another method?

Any good info on program design?

Writer's Block
Advertisement

Mmh, when the function seems not to fit with its class, then maybe you should create another class.

For exemple if you have a class which purpose is cookie business, and you need to implement a function that feed cats then maybe you should create another class dedicated to cat-business.

My exemple is kind of silly, but its the idea. Specialize your class. Each class should do one thing. Cookie-business (baking cookie, selling cookie, creating cookie-recipe) or cat businness (feed cat, play with cat, breed cat), not both.

On the contrary don't overdo it and create one class for each function you will make ^^'

Anyway, try to be as coherent as possible with your code. And trust your feelings :D

Yep, there's lots of useful information in the web. You shoud research on the Single Responsibility Principle (SPR).

The Single Responsibility Principle states that a class should have one and only one well defined responsibility. In resume, if the method you are about to add is needed for the class to perform its responsibility or purpose, it belongs to that class, otherwise, you should create a new class. The hard task here usually is to define that responsibility, but that comes with time and practice.

For instance, let's suppose I want to build a car, and I have a component Engine which is responsible for putting the vehicle in motion. My Engine class has a method accelerate(). After that, I discover that depending on the situation, my engine needs to perform in a different fashion, so I add a method changeGear(). Allright, now my Engine can put the vehicle in motion, and switch gears so it can perform better. Then I realise that, in some situations, perhaps I would like to be able to stop the vehicle, so I add a method decelerate() to my Engine class. Now, I have a class that is responsible for accelerating and decelerating the vehicle, which violates the SPR. What I should do is create a new class Brake with the method decelerate().

The example is very basic and has some flaws, we can have distinct views about what "putting the vehicle in motion" means, or what should be the Engine responsibility, but I think it ilustrates the concept.

Further on the single responsibility principle...

A class should focus on a single responsibility. Every function of the class should support that single responsibility. Every data member of the class should be related to the responsibility.

There are several related concepts, such as dependency inversion, the substitution principle, and more, known as SOLID.

Deciding exactly what responsibilities belong to a class can be a difficult decision. When you are too generic (such as "ResourceManager") you tend to create a "god class" that does too much or knows too much. When you are too specific you have classes that are incomplete and require tight coupling to be useful. Often there are clusters of functionality, such as an ImageCache, ImageProxy, CacheEventHandler, or whatever more you need. Or that may be overkill for your design.

When you discover them, find a way to refactor or redesign the code if it helps. Sometimes classes need to be split. Sometimes they need to be merged. Sometimes dependencies need to be introduced, frequently dependencies need to be removed. Sometimes it is better to just live with the mistake.

There are several classes that naturally become god classes in games. Often there is a GameObject that contains a bunch of generic information that applies to absolutely every object. There may be a World class that serves as not just a container for objects in the world, but also a central hub for everything remotely related to the simulator. Physics, Sound, and Animation turn into dumping grounds or namespaces with way too many free-floating functions. Keeping them limited to a single responsibility can be difficult, but it makes for a better implementation.

Trying to enforce a single responsibility per class often requires experience to do well. Most of us gain experience by watching others or by doing it badly and getting burned. As this is For Beginners, just do your best and focus on getting something that is functional. It doesn't need to be perfect, focus on the minimum to be good enough for your needs. In the process you will gain a lot of experience (by doing things badly). Don't worry too much about it if you can make it work. Live with the bad version for now, just get the project finished any way you can. Finish off your tic tac toe game, or pong game, or falling block game, and each time you will learn many things to do differently on your next, more ambitious project.


Most of us gain experience by watching others or by doing it badly and getting burned.

For some reason I keep choosing option B -- getting burned by doing it badly.

There are mountains of information on the 'Net, but I've found great inspiration for class design in -- believe it or not -- programming resources for business applications. Their militant methods of DRY (Don't Repeat Yourself) and the hurtful and informative mantra "Keep It Simple, Stupid" (KISS) allowed me to focus on the thought process behind designing classes and interfaces without getting bogged down in game-related or engine focused information.

Indie games are what indie movies were in the early 90s -- half-baked, poorly executed wastes of time that will quickly fall out of fashion. Now go make Minecraft with wizards and watch the dozen or so remakes of Reservior Dogs.

"Keep It Simple, Stupid" (KISS)

Best mantra ever :D

Also, learning some design pattern could help you figure thing out and give you ideas. I recommend this very good book about design pattern : http://shop.oreilly.com/product/9780596007126.do

Even if it's explained with Java, the theory can be applied to any languages.

Single-Responsibility Principle.

Stated another way, functions, classes and modules should strive to this mantra: "Do very little, very well."

You get into a very philosophical question of "What is a single responsibility?" pretty quickly, and it depends on the level on which that element operates. For two numbers, adding and subtracting are each single responsibilities. For a string, a single responsibility might be concatenating two strings together, or finding the first occurrence of a character. For a database, a single responsibility might be inserting a row of data atomically.

A simple rule of thumb is this -- describe in some detail the essence of what the function, class, or module does in just one sentence. If you can do it without using a conjunction -- usually "and", but sometimes "or" -- you're probably golden. If you struggle to fit it into a sentence or can't do so without reaching for a conjunction, then it's a sign that it might do too much -- that it might have more than one responsibility. It doesn't *always* mean that, strictly speaking, and sometimes you just have to accept it for practical reasons (preferably late in the game, you should be less willing to compromise early on), but it should always make you cast a suspicious eye towards it.

throw table_exception("(? ???)? ? ???");

This topic is closed to new replies.

Advertisement