Object Oriented musings

I’ve been in software development for a long time and most of that time has been spent using object oriented languages, including C++, Java and C#. I’ve made plenty of mistakes along the way and I think I have a good guide how to and how not to use some aspects of OO.

A classic OO introductory example I’ve seen is as follows:

class Car{
    const double ACCEL = 1.5;
    double Speed;
 
    void Accelerate(){
        Speed += ACCEL;
    }
}

All makes sense, then I want to add some “real world” logic involving things external to the car. Like, what if the car is going up hill, is running into something or on a slippy surface? I would inevitably end up passing global state to the “Accelerate” method:

class Car{
    const double ACCEL = 1.5;
    double Speed;
 
    void Accelerate(World world){
        // Funky logic involving the World
    }
}

At this point, things are getting confusing because logic is spread between the World and the Car. This gets even worse if inheritance is involved. Imagine a “Vehicle” base class that “Car” inherits from, then a “Motorbike” class that has slightly different acceleration logic involving wheelies etc. This could be sold as “extensible” because I can drop in some other kind of  vehicle without tinkering with the World class. However, this is a maintainability disaster with logic spread out everywhere and logical problems with ordering of calls (think 2 cars accelerating into the path of each other). This example may seem abit contrived, but I’ve seen numerous examples of a “Save” or “Draw” method on a class that embodies the thing to be saved or drawn. In these situations it’s actually worse. What happens if I want to use a different database or rendering engine?

I’ve found that the only way to avoid madness is to ensure that logic is grouped together aggressively. So in our simple example, you’d end up with something like this:

class World{
    List<Vehicle> Vehicles;
 
    void RunWorld(double tick){
        foreach(var vehicle in Vehicles){
            // Common logic incl crash detection
            if(vehicle is a Motorbike){
                // Wheelie logic
            }
        }
    }
}

Now, you might think that this is just moving the logic around. However, I’ve noticed that all the classes like “World” (or “Database” or “RenderingEngine”) are essentially either static, singletons or contexts that are used against static / singleton type classes. These are ideal candidates for an interface and some sort of IoC framework to load in the implementation at runtime.

Heuristics

As a form of guidance, I’ve come up with a set of heuristics to follow when defining a class model. . but it’s a decent starting point.

  1. Identify if a class is one that is static, singleton or a context / wrapper (e.g: Database, Graphics System or World) / wrapper or whether it’s one that carries data (Record, Car or Game Character).
  2. If it’s the former (maybe call these “modules”, borrowed from Javascript?), this is a good place to centralise “business” logic. There is usually little scope for inheritance in these type of classes and they end up implementing a collection of interfaces.
  3. If it’s the latter,
    • Limit methods to only those that affect the data within the object. So Sort(), Validate(), AddX() should all be ok.
    • Drive behaviour from data (via the  “modules”), not methods on the objects.
    • Subclass for common data (maybe all records have a timestamp?) not to add logic in methods.

There will of course be exceptions. For example, I’ve been part of developing an expert system and validation classes. In these cases the logic was intentionally tied to the data carrying objects to that they could be built into a tree (using the composite pattern) and chained (Jquery style) respectively. These cases worked really well, and at least armed with the heuristics described, we could consciously weigh up a different approach.

 

 

Advertisements
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: