One of the disadvantages of object-oriented development is that it can, and often does, mean a more slowly performing application. Unfortunately, this has more to do with a lack of care when designing objects than it does with a fundamental flaw in object-oriented development.
First, you must realize that every development project requires balance. No project is without certain drawbacks. For a certain investment in time and money, there's only so much quality, so many features, and so much performance that you can buy. There's no way to have the highest quality software, along with the most features and the best performance, without spending a great deal of time and money.
In any software development project, you must focus on which performance characteristic is critical and make compromises on other less important areas. Of course, if you have unlimited time and money, then you will have more flexibility than those of us with time and money constraints.
In many cases, performance is one of the criteria that is considered last - and in today's world of high-speed processors, that may be the right answer. However, it's not possible to completely ignore performance without eventually having performance issues.
Only what you need
An economical way to address performance is by creating lightweight objects - in other words, objects that only initialize what they need when needed. An object should be a full-featured way for the user to utilize a specific kind of information; however, providing a full-featured solution doesn't mean that you have to completely prepare all of the features. You can wait until the feature of the object is needed and then initialize it.
For instance, a product object may allow you to view the extended attributes of a product. However, it may not be necessary to initialize those extended attributes if the user doesn't ask for them. This can substantially reduce the amount of time necessary to create an instance of the object. This is important when you need to initialize large numbers of objects, such as when you display an object list.
Patterns for lightweight objects
Creating a lightweight object involves an internal field, a sentinel value, and an initialization function. These work together to allow you to selectively initialize parts of the object as needed.
The property is what the user of the object uses to access the functionality. This is so that the call can be intercepted with a small amount of code to determine whether or not the functionality is already loaded.
The way that the property determines if the functionality is loaded is to look for a sentinel value in the internal field that, if present, indicates that the functionality has not been loaded. The sentinel value is set during the constructor for the object or during the object's initialization. Thus, if the field has any value other than the sentinel value, it has been initialized.
In some rare cases, you may not be able to determine the state by utilizing a sentinel value. In those cases, a Boolean flag is used to determine if the functionality within the object has been initialized.
If that portion of the functionality hasn't been initialized, the private initialization function is called. This initialization function initializes all of the functionality - or throws an error if unsuccessful. Once the initialization function has completed, the control is returned to the property, which can then return the internal field.
Picking properties and methods
Now that you have a pattern for how to make the object lightweight, it's important to decide which properties and methods you want to make lightweight. When making that decision, it's important to consider how many times the object will be created, the amount of effort required to make the request when the developer-user first asks for the extended functionality, and the amount of time that will be saved.
In general, you need to make a property or method lightweight when the object will be initialized fairly regularly as a course of the application, and the performance necessary to initialize the functionality in the object will take substantial resources. For instance, any remote call to get information, such as a database call, is probably worth making lightweight.
Conversely, objects that are only created once or functionality which won't save much in the way of resources are probably not worthy of consideration for becoming lightweight.
Coupling where necessary
A final tactic for making lightweight objects is allowing collections to initialize the object differently than any other user of the object. In general, each object is initialized by providing its key identifying information, and the object loads itself from a database. However, this doesn't take into account the efficiencies that simultaneous retrieval of multiple database records can create. In order to accomplish this, collections are allowed to initialize objects with a record from a query result set instead of utilizing the standard methods of construction.
This technique is allowed from the collection since collections are tightly coupled with the object that the collection holds. In this way, the collection can control the kinds of collections of objects and can allow objects to be initiated much quicker than if you were to initialize each object individually.
This technique can be very powerful since it leverages the native behavior of set based database results.
Object-oriented design doesn't have to lead to performance problems. While performance can be an issue, creating lightweight objects from scratch or adapting existing objects can dramatically improve performance with very little effort.