OOP – Do Objects in Object-Oriented Programming Have to Represent an Entity?

classentityobjectobject-orientedprogramming-languages

Does an object have to represent an entity?

By an entity I mean something like a Product, Motor, a ParkingLot etc, a physical, or even a clear-cut non-physical conceptual object — something that is well defined, with some core data clearly belonging to the object, and some functions/methods that clearly operate on the core data.

For example, I can have an object of a Demon, an entity in itself, an imaginary one perhaps and not physical but an entity nevertheless

Can an object be just a collection of methods, a common set of procedures that tie in with a common goal?

Example: can a class be called MotorOperations or MotorActions, where there is no entity, but methods inside the class do things like

  • getMotorDataFromHTMLForm()
  • getMotorManufacturers()
  • selectMotorFromUserRequirements($requirements)
  • canMotorCanHandleOperatingConditions($conditions)
  • computePowerConsumptionForMotor($id)

A class is typically defined as data central to the object + operations on data. So for a Motor there may be some motor variables relating to motor specifications, and there can be operations that combine those data to produce something.

In my case it is more like I have a class with operations on data + data that is passed through the class, there is no data centric to "Motor Operations", other than temporary pass-through-the-class data.

Question

Can classes represent entity-less objects?
If not, why they are bad/incomplete/non-OOP-centric? Are there ways they need to be changed/improved conceptually to be in line with OOP?

Best Answer

No, an object does not have to represent an entity.

In fact, I would argue that when you stop thinking about objects as physical entities is when you finally get the benefits that OOP promises.

This isn't the best example, but the Coffee Maker design is probably where the light started to come on for me.

Objects are about messages. They're about responsibilities. They're not about Cars, Users, or Orders.

I know we teach OO this way, but it becomes apparent after a few tries how fundamentally frustrating it is to figure out where things go when you try to do MVC, MVVM or MVWhatever. Either your models become ridiculously bloated or your controllers do. For navigability, it's great to know that anything that touches Vehicles is in the Vehicle.ext file, but when your application is about Vehicles, you inevitably end up with 3000 lines of spaghetti in that file.

When you have a new message to send, you have at least one new object, and perhaps a pair of them. So in your question about a bundle of methods, I would argue that you're potentially talking about a bundle of messages. And each one could be its own object, with it's own job to do. And that's ok. It will become apparent as you split things apart which things really, really need to be together. And you put them together. But you don't immediately drop every method in a vaguely appropriate drawer for convenience sake if you want to enjoy OO.

Let's talk about bags of functions

An object can be just a collection of methods and still be OO, but my "rules" are pretty strict.

  1. The collection should have a single responsibility, and that responsibility can't be as generic as "Does stuff to motors". I might do such a thing as a service-layer facade, but I'm acutely aware that I'm being lazy for navigability/discovery reasons, not because I'm trying to write OO code.

  2. All the methods should be at a consistent layer of abstraction. If one method retrieves Motor objects and another returns Horsepower, that's probably too far apart.

  3. The object should work on the same "kind" of data. This object does stuff to motors(start/stop), this one does things with crank lengths, this one handles ignition sequencing, this one takes an html form. This data could conceivably be fields on the object and it would seem cohesive.

I generally build objects of this sort when I'm doing transforms, composition, or just don't want to worry about mutability.

I find focusing on object responsibilities leads me towards cohesion. There has to be some cohesion to be an object, but there doesn't need to be any fields nor very much behavior for it to be an object. If I was building a system that needed those 5 motor methods, I would start out with 5 different objects that do those things. As I found commonality, I would either start to merge things together or use common "helper" objects. That moves me into open/closed concerns - how can I extract this bit of functionality so I never have to modify that particular file again but still use it where needed?

Objects are about messages

Fields barely matter to an object - getting and setting registers doesn't change the world outside the program. Collaborating with other objects gets the work done. However, the strength of OO is that we can create abstractions so we don't have to think about all the individual details at once. Abstractions that leak or don't make sense are problematic, so we think deeply (too much, maybe) about creating objects that match our mental models.

Key question: Why do these two objects need to talk to each other?

Think of the object as an organ in a person - it has a default purpose and only changes behavior when it receives a specific message that it cares about.

Imagine a scenario where you're in the crosswalk and a car is coming fast. As the brain object, I detect a stressor. I tell the hypothalamus to send corticotrophin-releasing hormone. The pituitary gland gets that message and releases adrenal corticotrophic hormone. The adrenal glands get that message and create adrenaline. When the muscle object gets that adrenaline message it contracts. When the heart get the same message, it beats faster. There's a whole chain of players involved in starting the complex behavior of sprinting across the street and it's the messages that matter. The brain object knows how to get the hypothalamus to send out the alert, but it doesn't know the chain of objects that will eventually make the behavior happen. Likewise the heart has no idea where adrenaline comes from, it just knows to do something different when that shows up.

So in this (simplified) example, the adrenal gland object only needs to know how to take ACTH and make adrenaline. It doesn't need any fields to do that, yet it still seems like an object to me.

Now if our application is designed only to sprint across the street, I may not need the pituitary gland and the adrenal gland objects. Or I only need a pituitary gland object that only does a small part of what we might conceptually see as the "pituitary gland model". These concepts all exist as conceptual entities, but it's software and we can make the AdrenalineSender or MuscleContractor or whatever and not worry much about the "incompleteness" of our model.

Related Topic