Nobody quite agrees what object-oriented programming is supposed to be. There is a multitude of sometimes contradictory and sometimes unrelated definitions and concepts associated with object orientation.
This note collects interpretations that I think are wrong, misleading, or incomplete.
For reference, I think that more useful interpretations are:
- Objects are polymorphic
- Objects communicate through message passing
- Objects are real world concepts
OOP is encapsulation, inheritance, polymorphism
Young programmers are sometimes introduced to OOP with a list of certain qualities that are thought to capture the essence of OOP:
- Encapsulation (information hiding)
Jörg Mittag (2014) explains on Software Engineering that these concepts do not uniquely characterize OO:
You can have inheritance without OO, you can have encapsulation without OO, you can have polymorphism without OO, you can even have all three at once without OO. On the flipside, you can have OO without inheritance. Plus, there are different kinds of encapsulation (ADT-oriented and OO), [in other words] not all encapsulation is OO.
The Design Patterns people also note that these concepts might be used outside of OOP systems:
Our patterns assume Smalltalk/C++-level language features, and that choice determines what can and cannot be implemented easily. If we assumed procedural languages, we might have included design patterns called “Inheritance”, “Encapsulation” and “Polymorphism.”
– Gamma et al. (1994): Design Patterns: Elements of Reusable Object-Oriented Software, p. 4
OOP is modular programming
In particular, encapsulation and abstraction are the hallmark of modular programming.
Wikipedia claims that class-based OOP has a lot of overlap with modular programming:
The relative importance of modules varies between languages, and in class-based object-oriented languages there is still overlap and confusion with classes as a unit of organization and encapsulation, but these are both well-established as distinct concepts.
In my experience, OOP features such as “classes” are most often used for modular programming only. These cases are easy to spot by classes that aren't subclassed and don't override any methods. This is perfectly acceptable design – not everything fits the OOP model! But if it doesn't actually use OOP, we shouldn't confusingly call them “objects”.
OOP is following SOLID principles
A bit more specific is invoking the SOLID principles as presented by Robert C. Martin (2005):
- Single responsibility principle (SRP)
- Open/closed principle (OCP)
- Liskov substitution principle (LSP)
- Interface segregation principle (ISP)
- Dependency inversion principle (DIP)
While these are usually phrased in an OOP-specific manner, they are all applicable more widely than just OOP. For example:
The Single Responsibility Principle is not just relevant on the class level, but on the level of any code unit: from single functions and methods up to whole libraries.
The Dependency Inversion Principle is about modules, not even about objects. It's just as applicable to header files in C.
The Open/Closed Principle isn't even worth following unless you are working on a library or framework, or when you have to maintain binary interface compatibility. Notably, application development usually doesn't have these very specific requirements.
Amusingly, the OCP doesn't even state “good OOP should follow the OCP”, but instead sees object-oriented techniques as a possible solution to extensibility problems.
Tony Marston (2011) has written an in-depth, balanced criticism of the SOLID principles .
OOP is good design
Since OOP has seen significant hype throughout the 90s and has been the predominant programming paradigm since the late 80s (and a notable paradigm since the 70s), many ideas of “good design” have been projected on this confusing and vague canvas. All the above concepts and principles are good, they just aren't very characteristic of OOP.