It's been years since I thought of this, but I am training some real juniors soon and need to explain what an object is to someone who doesn't know what it is.
Based on what you use in the real world, what are the key points of objects that I should focus on explaining. For example:
- Access Levels
- Inheritance
- Encapsulation
- Polymorphism
- Abstraction
- Interfaces
Back when I was learning OOP, I was puzzled by all these "car / animal / whatever" metaphors. They didn't help me at all. Then someone said that a class/object is just a set of variables (class members) and functions to deal with them (methods) - which is actually true. It was that simple!
Using all these popular metaphors is just misleading people, IMHO. Cars don't have that much in common with OOP. It's easy to understand these metaphors when you already know what they mean, but trying to begin with them... no.
I like the original metaphor used by Alan Kay, who coined "object-oriented programming": Objects are like cells in a body. They are each programmed with their own behaviors and communicate by passing messages to one another, which they again respond to with their own internally defined behavior. No one cell knows what's inside another — they just know how to handle their own tasks and communicate with each other.
I prefer the approach used in "Object-Oriented Design and Patterns" by Hortsmann. If I recall correctly, the approach was to read a problem statement and identify the objects, their methods, relations, and other components using a simple pattern. For instance, an object is a noun, so all nouns would be candidate objects.
The book itself is highly recommended. After establishing what an object is, it uses some clearly defined and simple examples to discuss inheritance, interfaces, and many design patterns like the singleton.
Haha...so I guess I really suggest you let someone else do it... an author(ity).
I prefer using real-life examples that you can actually interact with: a dish-washer, a car, ...
These things also happen to have a very strict interface: a car (in Europe :)) has an Acceleration pedal, a Break and a Clutch. You can ask for it's current speed.
Encapsulation: no need to know how the engine works if you know the interface. A good thing that you don't have to tinker the engine yourself, too.
Polymorphism: you can drive a Lada and a Porche using the same interface. This means you are a polymorphous driver :).
Note: it's taken me years to differentiate the concept of an interface from inheritance. I would say: leave inheritance out for a while: most of the time code reuse is achieved better by composition (though that's a whole other discussion).
If I were trying to explain classes and objects to someone completely unfamiliar with programming, I would probably use something along the lines of the following:
A class is just a "recipe for a thing", the class is made of different types of "ingredients" that have different characteristics (i.e. PODs and functions/methods).
So, in that it only contains descriptions of a layout (building blocks) and functionality.
Ingredients may be of different type: "data" in that they contain actual data fields (think facts stored in variables/fields), and "action" in that they contain specific methods to do things.
Some ingredients may be secret, you may not want to share all ingredients or you may not want to share some specific ways of doing specific things with the recipe (encapsulation).
So, you as the cook have the possibility to restrict access to ingredients, so that users of your recipe have to adhere to your recipe and simply use "pre-canned" steps (methods) of doing things that you provide (without them necessarily knowing what it is about):
Some ingredients may be meant to be only internally visible (private access) because they are only really relevant to that specific instance/manifestation of the recipe/class, while others may also be meant to be accessible from recipes that are based on this recipe (think customizations), that derive from it (protected access).
And then there are ingredients that shall be generally visible and accessible to all users of the recipe (public), because they compose the "frontend" or "interface" of the final product (they don't necessarily need to know about internals/low level implementation stuff).
Once a class is actually used to implement a particular recipe, a new object is created (the class gets instantiated): A chocolate cake is just one manifestation/version of the chocolate cake recipe. There can be many other versions using the same "recipe".
If you were to combine multiple recipes (e.g. chocolate cake and lemon cake), you can create a new recipe that derives from both recipes, basically creating a completely new recipe that shares the characteristics of the original recipes (multiple inheritance).
By basing new recipes on existing ones using inheritance, changes in the original recipe can be directly imported into the new recipe. Similarly, having a common ancestor recipe (type/super class), means that its very properties (fields and methods) can be expected in all sub classes (inherited/child recipes), in other words a generic "chocolate cake recipe" might be used to create two new specialized versions of a chocolate cake: "white chocolate cake" and "dark chocolate cake", where the color of the chocolate merely becomes an attribute that may be configurable using a chocolate cake specific method like "setChocolateColor()".
If you want your recipe to provide a way for new recipes to override some components of your recipe, you can provide boilerplate actions (methods) that can be individually overriden (virtual inheritance).
My experience as a self-learner is that I introduced a fair amount of trouble in my head with the concept of object as mapped to a "real entity" like animals and cars and so on. It forms your head in willing to find a realistic (as in "the real world") taxonomy in your business objects even when there's none, and it confuses you in finding unrealistic taxonomical classification that are instead useful for real OO design (eg. design patterns). Finally, it pushes you to the point that you fossilize in one "real world" taxonomy even if other "less real world" can exist and they are better.
In any OOP book you find that a square is a kind of rectangle, and so a square is represented as inherited by a rectangle, but we know that this approach is deeply flawed (I read a paper on that, don't remember where, but you can search about the "fragile base class problem" in google). Also, in some programming languages, you don't need OO taxonomy for interface inheritance (see my post on this regard).
So, my suggestion is: present it but be very careful how far you go, and eventually switch immediately from the "car and animals" examples to a less nice to present taxonomy. You can deeply flaw their understanding if you push it too far.