Object Oriented Programming Explained - Part 1 - The Basics
Procedural:
Struct Customer {
int customerId
String firstName
String lastName
String memberSinceDate
}
function int createCustomerId() {
return DB_createNewEmptyCustomerRecord();
}
function String getFullName(Customer customer) {
return customer.firstName + " " + customer.lastName;
}
function String getLengthOfMembership(Customer customer) {
return Dateutil_getYearsAndMonthsReadable(Dateutil_SubtractDates(customer.memberSinceDate, Dateutil_CurrentDate()));
}
}
Struct Product {
int productId;
String name;
}
}
Struct Order {
int orderId;
int customerId;
array productIds;
String orderDate;
boolean isFilled;
}
}
// get the current order
Order order = Database.getCurrentOrder();
// log the order
Print "Processing order #" + currentOrder.orderId;
Customer customer = DB_getCustomer(order.customerId);
Print "Customer is " + getFullName(customer);
Print "Customer has been a member for " + getLengthOfMembership(customer);
//decrement each product from inventory
for int i in length(currentOrder.productIds) {
Product product = Database.getProduct(currentOrder.productIds[i]);
DB_decrementProductFromInventory(product);
Print "Customer Ordered Product " + product.name;
}
Object Oriented:
(private) Integer customerId
(private) String firstName
(private) String lastName
(private) Date memberSince
// returns the customer ID if one exists, otherwise creates a new customer id and returns that
public int getCustomerId() {
if (customerId == null) {
customerId = Database.createNewEmptyCustomerRecord();
}
return customerId;
{
public String getFullName() {
return firstName + " " + lastName;
}
public String getLengthOfMembership() {
return (Date.currentDate() - memberSince).getYearsAndMonthsReadable();
}
}
(private) int productId
(private) String name
public String getName() {
if (name == null) {
return "No Name Available";
} else {
return name;
}
}
(private) int orderId
(private) Customer customer
(private) List<Products> products
(private) Date orderDate
(private) boolean isFilled
public int getOrderId() { return orderId; }
public Customer getCustomer() {
If (customer == null) {
customer = new Customer();
}
return customer;
}
public List<Products> getProducts() { return products; }
}
// get the current order
Order currentOrder = Database.getCurrentOrder();
// log the order
Print "Processing order #" + currentOrder.getOrderId();
Print "Customer is " + currentOrder.getCustomer().getFullName();
Print "Customer has been a member for " + currentOrder.getCustomer().getLengthOfMembership();
//decrement each product from inventory
for each product in currentOrder.getProducts() {
Database.decrementProductFromInventory(product);
Print "Customer Ordered Product " + product.getName();
}
Do you see the differences here? Subtle as they may appear, they are significant. While both approaches offer the same functionality, it's how they provide the functionality that is important to the software developer. OO is all about delegation. In this example, more work is done outside of the order-handling code on the OO side than the procedural. This is important, because the implications are that over a longer period of time of development, there is less code written at the higher levels because of the fact that more is done on the lower levels. The classes outlined here are generally known as Entity classes. Entity classes are ones which model a problem domain and act upon the data. In the OO side, the entity classes can be responsible for retrieving additional data, performing calculations, concatenating strings, persisting themselves and other tasks. While it's the same functionality to have memory-static functions that are passed a struct to operate off of, the concept is that the classes themselves are responsible in their own memory space for what they do. Notice the little things, like how if Product.getString() is called and there is no name, instead of returning null it returns "Not Available." This means less application code, because you may have 50 spots in your application which print the name and that reduces your work by 50 if/then statements!
Imagine if this system had much more robust functionality. Think order processing, invoicing, warehouse integration, executive reports, etc.. You name it. Those same entity objects will be reused throughout the system. Why not put as much reusable code in them as you can so you can minimize time developing the additional features of the application?
There is a much more technical benefit here as well. A struct is a struct. It holds data. It can be referred to by a single variable holding the pointer to the struct. Functions can be passed a struct and they can work on the struct's data. The struct, however, can not hold methods. In OO, methods belong to a class and what the means is that once a class is instantiated (new), any non-static method you call in the object (an object is an instance of a class) operates on the memory in it's instance and does not interfere with other other instances unless you explicitly write it to. If this doesn't seem significant, think about multi-threaded code.
The other benefit to putting methods in with an object is the organization of code. I don't need to know to find a function somewhere that performs operations on my struct. I can see what's available for my object (in a well designed codebase) right in the code. There's the class, and there are it's capabilities. It answers the question, "What can this class do?" While you can still create static util classes in any OO language, and there are reasons for doing so sometimes, you'll find that things can be easier to organize when written in OO.
Object Oriented Languages are made to be extensible.
Extensibility means that you can start with basic functionality and add more as you need it. This brings us to our next topic which is inheritence. I've heard many people complain about inheritence. I've seen people create examples of spaghetti code using inheritence. Of course you can manipulate a language to make a complete mess of it if you really want to. That doesn't prove that it's bad. It proves that you're good at making a mess of things.
Let's say that we originally wrote the system in the above example to support Products. All we knew when we started writing it was that a Product has an ID (to make the database side work) and a name. Now we want to add a table to the database which has product specifications which apply only to the specific type of product we're talking about. Our first implementation if this new design will be for a Product called a laptop. We do this by extending the class Product with a new class called Laptop.
(private) decimal screenSize;
(private) Speed processorSpeed;
(private) int hardDriveSize;
}
Think of it like this. A Laptop is a Product, but a Product is not necessarily a Laptop. Remember doing this logic puzzles on standardized tests when you were younger? It's like that. What this means is that you can add a new table for the laptop fields in your database and start adding laptop specifications in the application but NONE OF YOUR OLD CODE BREAKS. That's the real benefit. Since you've just extended the Product class, everything that used it still works fine. Why does it work? Because everywhere that you see a method which takes a Product as an argument, you can give it a laptop and it will use the Product fields it knows to exist but won't mess with any of the Laptop fields. Those can be used by all your new code and your new code alone.
Here's a more thorough example:
(private) int productId
(private) String name
public String getName() {
if (name == null) {
return "No Name Available";
} else {
return name;
}
}
}
Class Laptop extends Product {
(private) decimal screenSize;
(private) Speed processorSpeed;
(private) int hardDriveSize;
}
Class Book extends Product {
(private) String author;
(private) Integer publishedYear;
}
Class OrderSystem {
public void orderProduct(Product product) {
placeOrder(product.getId());
Print "Product " + product.getName() + " ordered.";
}
}
Order-Handling Code:
Laptop laptop1 = Database.getNextLaptop();
Laptop laptop2 = Database.getNextLaptop();
Book book = Database.getNextBook();
orderProduct(laptop1);
orderProduct(laptop2);
orderProduct(book);
Why does this work? It's because Laptops and Books are products and the order system (unlike the display system which shows you your details when you're shopping) doesn't care about what kind of product it is, it only cares that it is a product. This means your code in the order system only knows how to deal with products, which may never change, but you can keep extending the functionality of your application without having to update that to work with more types of products.
What I've shown here is the absolute most basic use of OO. If you stop now and say, "So, that's it?? What's the big deal?" You'll be missing out on the good stuff. This is just the primer to try to explain basic object modeling and OO concepts. We'll use these to do some much more interesting work which has very, very practical application.
This is a good time to segway into polymorphism. Read the next article in the series to continue.
Related Articles:
Object Oriented Programming Explained - Part 2 - Polymorphism
How to start writing software: Web Applications
How I became a professional software developer
Categories
Editorials3 TrackBacks
Listed below are links to blogs that reference this entry: Object Oriented Programming Explained - Part 1 - The Basics.
TrackBack URL for this entry: http://www.rbgrn.net/blog/mt/mt-tb.cgi/52
Wikipedia defines polymorphism as "the ability of objects belonging to different types to respond to method calls of the same name, each one according to an appropriate type-specific behavior." There is nothing too fancy about polymorphism other ... Read More
Hibernate is an excellent tool which saves many projects from substantial amounts of code. Gone are the days of writing massive datasource layers full of obnoxious JDBC code. As gravy you also get simple query objects, caching, connection p... Read More
If you have a need to use the command pattern and want to have a standard interface but with type safe parameters, I have come up with a solution. This is one of the most interesting uses (or hacks) of... Read More



Hey, it's 2007! Procedural is dead. Polymorphism and encapsulation have won. The fight now is between OO and more flexible, expressive ways of achieving those things.
You'd be surprised at how many people don't think that's true. I know many who are steadfast in their procedural ways. There's a time and place for everything in my mind, though. I intend on getting much more advanced in future articles. Stay tuned!
this is not a good practice at all, "No name Available" is also a name, you're forcing the client to check for this if he needs to display another message for example.
public String getName() {
if (name == null) {
return "No Name Available";
} else {
return name;
}
And with this style you'll end up with loads of types of products and for each new you have to create a class.. Isn't properties enough?
Class Laptop extends Product {
(private) decimal screenSize;
(private) Speed processorSpeed;
(private) int hardDriveSize;
}
I was simply trying to show the benefits of encapsulation. I wouldn't do this specific thing in the model because of the reason you pointed out. To some people it is a new concept and a benefit of OO that can go realized in other places in other ways.