There is no consensus on what exactly distinguishes object-oriented programming.
Historically, OOP was first “discovered” in the context of simulations, where objects literally represented physical objects and methods on these objects represented external events that the objects can react to. The general consensus is that this is not a good way to write software, but that the underlying principles can be very valuable.
One problem with modelling physical objects is that this misleads the design to include irrelevant relationships between objects, and irrelevant properties of the objects. Also, it is often more helpful to model abstract concepts instead of physical objects.
A more modern view does not see OOP as a technique to translate models into code, but sees object-orientation as a way to solve various problems through polymorphism, primarily interface inheritance.
This is usually a bottom up approach: I have different things that behave differently, but I want to use them as if they were the same type of thing. Without OOP, I have to look at each thing to find out what it is, then execute the correct behaviour.
Instead, I can define an interface that describes how I want to use them. Then I make my existing things conform to this interface, either if they inherit the interface or if I create an adapter between the interface and a specific thing. Now I can tell the things what to do, and they can perform their individual behaviour without me knowing their real type, because they conform to the interface.
It turns out that OOP is an excellent way to achieve modularity and extensibility. By depending only on interfaces instead of on concrete types, I can swap out implementations without further changes to the system (often through a “dependency injection” mechanism). One consequence is that object-oriented systems are easier to test in isolation than procedural systems, because I can easily replace the real dependencies with stubs or mock objects.
Not every software system needs this kind of flexibility. Many problems are a very good fit for non-polymorphic models. Quite often, a
class is not used because we want to do OOP, but because that's the only mechanism in the language to implement record types. Most method calls
instance.Method() are not polymorphic, but just a convenient abbreviation for what is effectively a static function
In addition to “OOP models the real world” and “OOP uses polymorphic techniques” there are also a number of other OOP interpretations:
- OOP is defined by Inheritance and Encapsulation (often taught in introductions to programming, but misses the point)
- Objects = Data + Behaviour
- Objects use open recursion (B. Pierce)
- Object-oriented systems are SOLID (Robert C. Martin)
- Objects communicate through message-passing (Alan Kay)