Object Oriented (OO) languages are a staple of the development community, however many people continue to argue against them, citing that they are inefficient, useless, confusing and unnecessary. There are many real benefits to using OO even for very small projects. It does require a different mode of thinking though to convert from a purely procedural environment into an OO one. In this article I will show some of the values added by implementing using OO designs and what is saved in the long run.
For those of you who haven't worked with OO much before or you've used an OO language but not adhered to the OO state of mind, I'll give you a few examples comparing how to implement something procedurally and how it's done in the OO world. My example will be a partial implementation of a product ordering system wherein a customer can place an order for a list of products. There will be an imaginary datasource connection layer that won't be written out here but you will see calls to some database interface. That's less important than the other concepts shown. Please note, for brevity's sake these are partial implementations and are in a fake language that represents what's possible with most modern languages. Also I'm going to assume strong typed languages in my example to help with readability. For each language I'll assume they have equivalent API functionality (that is I won't make up things for one that I don't make up for the other.)
Procedural:
File (customer.code) {
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()));
}
}
File (product.code) {
Struct Product {
int productId;
String name;
}
}
File (order.code) {
Struct Order {
int orderId;
int customerId;
array productIds;
String orderDate;
boolean isFilled;
}
}
Order-Handling code:
// 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:
Class Customer {
(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();
}
}
Class Product
(private) int productId
(private) String name
public String getName() {
if (name == null) {
return "No Name Available";
} else {
return name;
}
}
Class Order {
(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; }
}
Order-Handling Code:
// 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.
Class Laptop extends Product {
(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:
Class Product {
(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.
Bookmark or Share this article:
Related Articles on Robert Green's DIY:
4 Comments
Post a comment here or discuss this and other topics in the forumsre: Object Oriented Programming Explained - Part 1 - The Basics
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.
re: Object Oriented Programming Explained - Part 1 - The Basics
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!
re: Object Oriented Programming Explained - Part 1 - The Basics
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;}
re: Object Oriented Programming Explained - Part 1 - The Basics
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.
Post new comment