1. Game Development
  2. Programming
Gamedevelopment

Quick Tip: The OOP Principle of Encapsulation

by
Difficulty:BeginnerLength:MediumLanguages:
This post is part of a series called Beginner's Guide to OOP.
Quick Tip: The OOP Principle of Coupling
Quick Tip: The OOP Principle of Abstraction

We've discussed object-oriented programming for game developers in general and the specific OOP principles of cohesion and coupling. Now let's take a look at encapsulation and how it helps to keep code loosely coupled and more maintainable.


Note: Although this Quick Tip is explained using Java, you should be able to use the same techniques and concepts in almost any game development environment.


What Is Encapsulation?

Encapsulation is the principle of information hiding. That is, the implementation (the internal workings) of an object is hidden from the rest of the program.

A popular example you’ll hear for encapsulation is driving a car. Do you need to know exactly how every aspect of a car works (engine, carburettor, alternator, and so on)? No - you need to know how to use the steering wheel, brakes, accelerator, and so on.

Another example is searching for a value in an array. In Java, you can do the following:

The above code will return true if the value 11 is in myArray, otherwise it will return false. How does the contains() method work? Which searching technique does it use? Does it pre-sort the array before searching? The answer is it doesn't matter because the exact implementation of the method is hidden.


Why Is Encapsulation Helpful?

Encapsulation helps to create code that is loosely coupled. Because the details are hidden, it reduces the ability of other objects to directly modify an object's state and behavior.

It also greatly helps when you must change the data type of a variable. Lets say you decided to use a String to keep track of time in "hh:mm:ss" format. After awhile, you come to realize that an int representing seconds might be a better data type for time. Not only must you change the data type in the object, but also every time you referenced the object's time in the entire program!

Instead, you can use what are known as getter and setter functions. Getters and setters are usually small functions that return and set a variable respectively. A getter function to get the time would look as follows:

The getter will return a String value: the variable time. Now when we want to change time to an int, instead of changing all calls to the getter we can just change the getter function to change the int data type into a String data type.

The % operator is known as the modulus operator and returns the remainder of a division. So 10 % 3 would return 1 since 10 / 3 = 3 with a remainder of 1.

The getter function now returns a String and none of the calls to the function have to change. The code is therefore more maintainable.


How to Apply This Principle

Asteroids

Lets go back to the example of a ship firing a bullet introduced in the coupling article. Recall that we defined a ship as follows:

To have the ship fire a bullet, all you would have to do is call ship.fire(). How the code implements firing a bullet is not important, because all we care about is firing a bullet. This way, if you want to change the code to fire a laser blast instead, you just have to change the method fire() and not every call to ship.fire().

This allows you to have the ability to change any aspect of how the ship works without having to change how the ship object is used everywhere else.

Tetris

Tetris has a few different ways to deal with clearing lines. Encapsulating the behavior of clearing a line will allow you to quickly change which method you use without having to rewrite each use of it. This will even allow you to be able to change the clear line method to create different modes of play in the game.

Pac-Man

There is one more feature of encapsulation that deals with hiding the access to an object. There are many times where you do not want external access to an object's state or behavior, and so want to hide it from any other object. To do this, you can use access level modifiers which give or hide access to objects' states and behaviors.

Access level modifiers define two access levels:

  • public - any object can access at any time the variable or function.
  • private - only the object that contains the variable or function can access it.

(There is a third level - protected - but we'll cover that in a future post.)

Recall that a ghost had states of:

  • color
  • name
  • state
  • direction
  • speed

...and was defined as follows:

Since changeColor(), changeSpeed(), and changeDirection() are helper functions and are not supposed to be accessed from anywhere else but inside the class, we can define them as private functions. All the states of the ghost can also be declared private since they shouldn't be modified from outside the class either, and only accessed through getter and setter functions. This would change the class to be defined as follows:


Conclusion

Encapsulation can help to create more maintainable code by helping to prevent the ripple effect of code changes. It also helps with creating loosely coupled code by reducing direct access to an object's state and behavior.

In the next Quick Tip, we’ll discuss the principle of abstraction and how it can help to reduce code redundancy. Follow us on TwitterFacebook, or Google+ to keep up to date with the latest posts.

Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.