Tonight we’re going to talk about “Design Patterns”.
What are Design Patterns, you ask? Design Patterns allow programmers to creatively refactor messy code-bases into collections of easily maintainable code. In other words, it’s our way of being artistic… except with code… because programming is an art… sort of. >_>
The most important goal of implementing Design Patterns is to create re-usability while eliminating as much redundancy as possible. In fact, I’d say getting into the habit of thinking that way is a good first step: “Always eliminate redundancy”. My Database 101 professor drilled that message into our heads when I took that class, and it’s served as the foundation to my approach for anything related to Computer Science. 🙂
So, what are some typical Design Patterns? Well, there are three primary categories: Structural, Creational, and Behavioral.
Structural patterns are defined by how your code is organized. Creational patterns are defined by how objects (as in Object-Oriented Programming) are brought into scope. And Behavioral patterns are defined by how objects communicate/interact with other sections of your code base.
So, given my desire to create a game engine, what are some practical Design Patterns I could implement?
The facade pattern encapsulates a series of interfaces into a single interface, thereby making it easier to access those interfaces without needing to daisy-chain their implementation within multiple classes. In my game engine context, that would mean creating a single header file that contains the import/include statements of other classes. I could, for example, include the headers for my controller input class, renderer class, physics class, and the list goes on. Inside my actual game file, I would just import this one header so I would have access to all of the tools I need to build my game, saving on line-space in the process.
The adapter pattern assists with making an incompatible interface capable of communicating with classes that it otherwise couldn’t. At least, not without significant revision. Since I mentioned that I’m using Irrlicht as my renderer and input-manager, I’m currently writing an adapter that will make it easier to interface with the API without exposing, or compromising, its original implementation. This pattern is also called the “Wrapper Pattern” and/or “Translator Pattern”.
I don’t actually think I’m going to be using any creational patterns just yet (at least not for the engine), as they may already be integrated properly within the tools I’m using. For educational purposes, though, here are some examples:
The singleton pattern provides a single point of access for a class, thereby making it impossible to be accessed multiple times within the same immediate scope while the application is running. It restricts global scope so that tasks cannot compete for access, or create multiple instances, of a specific object. My “game” class could be implemented as a singleton, because there is only supposed to be one instance of it.
-Abstract Factory Pattern-
The abstract factory pattern allows the user to create objects without exposing those objects’ underlying implementation. If I were building a game about… well… “buildings”, I could implement a “Create Building” class that allowed me to create many different types of buildings based upon user input at run time. The factory would contain methods linked to the constructors of each individual building type, which (more than likely) inherit from a parent “Building” class. Most objects created inside of any factory pattern typically inherit from a common interface.
These are some of my favorite design patterns. I was a Communication Major in college, so I have a deep appreciation for concision and efficiency regarding the communication between objects.
The mediator pattern defines an interface that abstracts the flow of communication between the caller (the class invoking the mediator) and the receiver (the class the mediator passes the invoker’s message along to). This promotes what is called “Loose Coupling”. Let’s use a DVD player as an example: Depending upon what type of media I insert inside of my DVD player, different functionality will occur. If I insert a music CD, the DVD player will act as a sound station. If I enter a DVD, the DVD player will begin playing the movie. The idea is that the mediator’s interface is able to identify which receiver needs to be accessed based upon what information it’s presented with by the caller. In this case, the caller is the media, the receiver is a specific feature of the DVD player, and the mediator is the interface of the DVD player itself.
In my game, I will be using a mediator to assist with managing different input schemes. Mouse and keyboard, gamepad/joystick, and touch gestures are all examples of different kinds of input. An input manager would enable me to create a layer of abstraction between the device running my game and my input implementation. It would allow my game to run on computers regardless of whether or not they have a keyboard, mouse, joystick, or touch screen. While it may seem similar to the abstract factory pattern, keep in mind that the main difference is that I’m simply managing behavior and not creating anything. Intent matters.
The observer pattern defines an interface that allows multiple objects to observe a single one. Any time an event occurs that requires notification of the subscribers, the observer provides a protocol for enabling this to occur. This pattern is also called the “Publish/Subscribe Pattern”.
If I were building a Real-Time Strategy game, I could create a layer of automation by structuring my code so that certain entities in-game would change their behavior based upon certain events happening. If my town is attacked, different entities could immediately engage in combat, shifting away from whatever other task they were performing. An observer prevents me from always having to directly manage the communication between my objects, and allows for a more asynchronous, less procedural, implementation.
Well, there you have it! Those are some nifty patterns to get you started, and there are plenty more besides the ones listed above. There’s also a great book on the subject written by the “Gang of Four“. I myself own this delightful bible of object-oriented programming, and I highly recommend that you purchase it if you begin to get serious about your game design efforts.
That’s it for now. See you next time!