Object Oriented Programming
From J. Arrizza Wiki
- 1 What is an Object?
- 2 Why use OOP?
- 3 Object Normal Forms?
- 4 Refactoring
What is an Object?
In Object Oriented Programming, what is an Object?
There are several layers of answers for this:
- An Object is an instance of a class
- An Object is a collection of methods (i.e. functions) and member variables
- An Object has a single purpose
- An Object is a collection of methods and variables that are associated together
- An Object is a collection of methods and variables that are strongly associated to the single purpose of the class
In the order listed, these answers refine the concept of an Object. The last is a very good definition of a well-designed Object.
It's an Instance of a Class
This is the most common answer.
The normal textbook answer, but it does not address why use Objects at all.
Also, while it is technically true for some languages like Java and C++, it is not true in other languages like Ruby and smalltalk. In these a class itself is an object and can be manipulated as an Object.
A similar answer is "OOP supports Encapsulation, Polymorphism and Inheritance". This is another textbook answer, but does not reveal a deeper knowledge of Objects. Also, it is clear that none of these is necessary for a program to use OOP. For example, it is possible to write an OOP application in Assembler, a language which has little if any support for these concepts.
It's a Collection of Methods and Variables
This is the next most common answer.
It is a better answer than the first in that it begins to outline why OOP may be a useful methodology. Collecting functions/methods and variables together is a first-cut attempt at OOP. This is a natural activity for programmers to do and was done even in Modular Decomposition Programming where functions were grouped together into "Modules".
Sometimes people say a class is similar to a Noun and methods are similar to Verbs. Again this shows that there is some underlying reason to group methods together. It does not address which functions and variables should or should not be in the class.
It's Methods and Variables are Associated
A rare answer.
This is a better answer again because it is much closer to the core of the definition of an Object. The Methods and Variables of a well-designed Object are not randomly chosen. They are associated in some way, but unfortunately this answer does not address why and how they are associated.
It has a Single Purpose
A rare answer.
A well-designed Object has a single purpose. It has the functionality and data to do one "thing" very well.
This is a good answer as well but does not tie in the methods and variables of the Object.
It's Methods and Variables are Strongly Associated with the Object's Purpose
In a well-designed Object:
- every method is strongly related to the Object's Purpose
- every variable is strongly related to the Object's Purpose
- every variable is usually one of these:
- an attribute of the Object, i.e. it describes a facet of the Object's Purpose
- a state the Object can be in
In other words, every method and variable is necessary and sufficient for the Object's Purpose. The Object contains only the code it needs and not any more than that. The Object is as complex as it must be and not more.
Why use OOP?
Simply, it tends to promote code that does not change. The #1 cause of bugs is code changes.
In a well-designed Object, the Object's Purpose is very clear and singular. Every Method is strongly related to the Purpose and so removing that Method would, in some sense, diminish the Object. Altering the Method (beyond bug fixes) also becomes unlikely since the Purpose is clear and the Method supports that Purpose. Adding additional Methods may occur but in popular or common Objects this will be very rare.
Similarly every Member Variable is strongly related to the Purpose and so removing, changing or adding Variables is a rare activity.
A well-designed Object with a clear and singular Purpose becomes a "magnet" for new behavior that supports that Purpose. As an application evolves, new behavior naturally splits up and attaches to the correct Objects. If the new behavior does not fit well in any of the existing Objects, it tends to suggest a new Object is required.
Based on all of these effects, a well-designed Object solidifies and matures. Changes become rare. The code becomes static, predictable and well behaved. Other Objects in the system can depend on them to behave the same way and do not change.
Bugs in a well-designed Object are:
- much easier to detect by inspection or code review
- much easier to fix
- have less impact on other parts of the code, i.e. fixing them does not cause "whack-a-mole"
- much easier to locate at the Application level. Since an Object has a single purpose, and the application is having problems behaving in some aspect X, then the Object(s) whose Purposes are to implement X are easier to identify.
Object Normal Forms?
Well-designed Objects seem to have a similarity to Database Normalization. In Third Normal Form "all the attributes in a table are dependent on the primary key and only the primary key". The Boyce-Codd Normal Form says "Each attribute must represent a fact about the key, the whole key, and nothing but the key."
Draw a line from the concept of a "primary key" in a relational database table to the idea of the Object's "single purpose" and then draw a similar line from the "attributes" in a database table to an Object's "member variables". And then paraphrasing the Boyce-Codd Normal Form: Each of the Object's member variables are directly and strongly related to the main purpose of the Object, to the whole purpose, and nothing but the purpose.
If a member variable is not related to the main purpose of the Object, it belongs, perhaps, in another Object. Can it simply be removed without affecting the Object's behavior?
If a member variable is related only to a portion of the Object's purpose, then the Object may be multiple Objects in one and subsets of the member variables describe each of the sub-Objects.
If a member variable describes (or is an attribute of) another member variable in the same Object, then there is a sub-Object that should contain the two (or more) member variables .
The primary intent of refactoring in OO applications is to disentangle two (or more) classes intertwined within an Object. There are other reasons to refactor, but the one gives the most benefit for the effort is "Extract Class".
Here are some of the symptoms:
- The Object's Purpose is vague or sprawling
- The Object's Purpose is clear but has one or more additional behaviors
- Contains methods/variables that do not relate to the Object's Purpose at all
- Contains methods/variables that are weakly associated to the Object's Purpose but strongly associated to each other
- There is a cluster of related methods that work only on one of the variables (e.g. open/read/write/close a file variable)
- There is a cluster of methods that have very similar signatures (i.e. the same formal parameters in all of them)
Rules of Thumb
- common method signatures