[1] I don't think I invented "Object-oriented" but more or less "noticed" what was really powerful about just making everything from complete computers communicating with non-command messages. This was all chronicled in the HOPL II chapter I wrote "The Early History of Smalltalk". — Alan Kay
Let's not have dashboard access the temperature by doing `GetSurroundingCar().engine.temperature`
If the dashboard needs to get the temperature from a sensor in the engine, it should be able to "talk" to the sensor, without going through car object.
In ideal OOP, a "method call o.m(...)" is considered a message m being sent to o.
In practice, field access, value and "data objects" etc are useful. OOP purism isn't necessarily helping if taken to the extreme.
The pure OOP idea emphasizes that the structure of a program (how things are composed) should be based on interactions between "units of behavior".
Then you should burn the whole thing down and start over!
I work on tractors not, cars, but I'm sure the abstractions are similar. Our engine objects are things like [service]AutomationEngine. Our dashboards objects are for a collection of things on secondary displays - meanwhile the thing you would point with your finger as the actual dashboard doesn't have or need a dashboard object. There is an object for things like RPM gauge, or check engine light - this later is a generic fault indicator with a icon field; it is connected to a different messages; and placed in different positions depending on the fault.
The point of the above isn't how tractors are designed, it is how the objects you need to design a real OO system rarely have anything to do with that looks like objects. Nobody ever writes dog and cat objects derived from animal; nobody ever writes triangle objects derived from shape.
2. Avoid overly complex function parameters and return values. Stick to passing simple primitives; strings, numbers, flat objects with as few fields as necessary (by value, if possible). Otherwise, it increases the coupling of your module with dependent logic and is often a sign of low-cohesion. The relationship between cohesion and coupling tends to be inversely proportional. If you spend a lot of time thinking about cohesion of your modules (I.e. give each module a distinct, well-defined, non-overlapping purpose), the loosely-coupled function interfaces will tend to come to you naturally.
The metaphor I sometimes use to explain this is:
If you want to catch a taxi to go from point A to point B, do you bring a steering wheel and a jerry-can of petrol with you to give to the taxi driver? No, you just give them a message; information about the pick up location and destination. This is an easy to understand example. The original scenario involves improper overlapping responsibilities between you and the taxi service which add friction. Usually it's not so simple, the problem is not so familiar, and you really need to think it through.
We understand intuitively why it's a bad idea in this case because we understand very well the goal of the customer, the power dynamics (convenience of the customer has priority over that of the taxi driver), time constraints (customer may be in a hurry), the compatibility constraints (steering wheel and fuel will not suit all cars). When we don't understand a problem so well, an optimal solution can be difficult to come up with and we usually miss the optimal solution by a long shot.