Ara Pehlivanian | February 1, 2011
What is OO?
Object-oriented programming basically represents physical, real-world objects that you want to work with in code. In order to create objects, you need to first define them by writing what's called a class. Classes can represent pretty much anything: accounts, employees, navigation menus, vehicles, plants, advertisements, drinks, etc... Then, every time you want to create an object to work with, you instantiate one from a class. In other words, you create an instance of a class which gives you an object to work with. In fact, the best time to be using objects is when you'll be dealing with more than one of anything. Otherwise, a simple functional program will likely do just as well. Objects are essentially containers for data. So in the case of an employee object, you might store their employee number, name, start date, title, salary, seniority, etc... Objects also include functions (called methods) to handle that data. Methods are used as intermediaries to ensure data integrity. They're also used to transform data before storing it. For example, a method could receive a date in an arbitrary format then convert it to a standardized format before storing it. Finally, classes can also inherit from other classes. Inheritance allows you to reuse code across different types of classes. For example, both bank account and video store account classes could inherit from a base account class which would provide fields for profile information, account creation date, branch information, etc... Then, each would define its own transactions or rentals handling data structures and methods.
There are three important things to note here:
This time, I've created a Human class which contains properties common to humans--I moved fname and lname there since all humans, not just employees have names. I then extended the Employee class by assigning a Human object to its prototype property.
Code Reuse Through Inheritance
In the previous example, I split the original Employee class in two. I moved out all the properties common to all humans into a Human class, and then caused Employee to inherit from Human. That way, the properties laid out in Human could be used by other objects such as Student, Client, Citizen, Visitor, etc... As you may have noticed by now, this is a great way to compartmentalize and reuse code. Rather than recreating all of those properties for every single type of object where we're dealing with a human being, we can just use what's already available by inheriting from Human. What's more, if we ever wanted to add a property like say, middle name, we'd do it once and it would immediately be available to everyone inheriting from Human. Conversely, if we only wanted to add a middle name property to just one object, we could do it directly in that object instead of adding it to Human.
Public and Private
I'd like to touch on the subject of public and private variables in classes. Depending on what you're doing with the data in an object, you'll want to either make it private or public. A private property doesn't necessarily mean that people won't have access to it. You may just want them to go through one of your methods first.
Sometimes, you only want a value defined once at the moment the object is created. Once created, you don't want anyone changing that value. In order to do this, you create a private variable and have its value set on instantiation.
In this example, I create a local array called data within the Animal class. When an Animal object is instantiated, a value for type is passed and set in the data array. This value can't be overwritten as it's private (the Animal function defines its scope). The only way to read the type value once an object is instantiated is to call the getType method that I've explicitly exposed. Since getType is defined inside Animal, it has access to data by virtue of the closure created by Animal. This way, people can read the object's type but not change it.
It's important to note that the "read-only" technique will not work when an object is inherited from. Every object instantiated after the inheritance is performed will share those read-only variables and overwrite each other's values. The simplest solution is to convert the read-only variables in the class to public ones. If however, you must keep them private, you can employ the technique pointed out by Philippe in the comments.
There are times however, that you'll want to be able to read and write a property's value at will. To do that, you need to expose the property using the this operator.
This time our Animal class exposes a property named mood which can be written to and read at will. You can equally assign a function to public properties like the getType function in the previous example. Just be careful not to assign a value to a property like getType or you'll destroy it with your value.
Finally, you might find yourself in scenarios where you need a local variable that's completely private. In this case, you can use the same pattern as the first example and just not create a public method for people to access it.
Writing a Flexible API
Now that we've covered class creation, we need to future proof them in order to keep up with product requirement changes. If you've done any project work, or maintained a product long-term, you know that requirements change. It's a fact of life. To think otherwise is to doom your code to obsolescence before it's even written. You may suddenly have to animate your tab content, or have it fetch data via an Ajax call. Though it's impossible to truly predict the future, it is possible to write code that's flexible enough to be reasonably future proof.
Saner Parameter Lists
One place where future-proofing can be done is when designing parameter lists. They're the main point of contact for people implementing your code and can be problematic if not well designed. What you want to avoid are parameter lists like this:
This class is very fragile. If you want to add a middle name parameter once you've released the code, you're going to have to do it at the very end of the list since order matters. That makes it awkward to work with. It also makes it difficult to work with if you don't have values for each parameter. For example:
A cleaner, more flexible way of approaching parameter lists is to use this pattern:
The first parameter is there because it's required. The rest is lumped together in an object which can be very flexible to work with.
The beauty of this pattern is that it's both easy to read and highly flexible. Note how
The code inside the class doesn't care because the values get accessed by index like so:
Make It Pluggable
As time goes on, product requirements might demand additional behavior from your classes. Yet often times that behavior has absolutely nothing to do with your class's core functionality. It's also likely that it's a requirement for only one implementation of the class, like fading in the contents of one tab's panel while fetching external data for another. You may be tempted to put those abilities inside your class, but they don't belong there. A tab strip's responsibility is to manage tabs. Animation and data fetching are two completely separate things and should be kept outside the tab strip's code. The only way to future proof your tab strip and keep all that extra functionality external, is to allow people to plug behaviors into your code. In other words, allow people to hook into key moments in your code by creating events like
This example has a simple TabStrip class with a showPanel method. The method fires two events, onShowPanel and afterShowPanel. It's given the ability to do so by augmenting the class with Y.EventTarget. Once that's done, we instantiate a TabStrip object and assign a bunch of event handlers to it. This is our custom code for handling this instance's unique behavior without messing with the actual class.
About the Author
Find Ara on: