tags:

views:

202

answers:

9

I'm working on a kind of a HMI application and is creating objects to define a specific machine. Lets say this is a car for the sake of argument.

A object for the engine is obvious. There are a few common sensors on the engine, and this is a few objects mounting to a few properties on the engine object. The throttle property is a input of course.

The car has atleast one door. Each door can have a window, it can be openable and it may be electrically operated. If it's electrically operated it will depend on power from the car to operate.

Now, should I expose the door as a property on the car object, or would it be most sensible to keep it private and having the car object operate the door in OpenDoor and RollDownWindow functions? What about events? Should I expose events on the engine, example LowOnOil event, or should I deal with it in the car object witch in turn could have an event like EngineIsLowOnOil?

How would you do this?

+8  A: 

This, and all similar questions, can be answered by considering why you are building the model. There is absolutely no point in creating a model in isolation from the problem you are trying to solve, and in general it is not possible to do so.

For example, if you are building an electronic fuel injection control, system, the number of doors on the car (and posibly even the car itself) is of no interest, and should not be modelled.

anon
Fuel injection system would be a object contained within the engine. Should the engine object then expose the fuel system as a property, or should it leave it private? Lets say it's turbo system and you want the turbo pressure... Expose only whats needed, or the whole fuel system?
rozon
@rozon, the general rule of thumb is only expose what you need. If you need to expose the Fuel System at a later date then it should be easy enough to do so.
James
Impossible to say without knowing the domain. You seem to bleive that there is a single "correct" way of producing an object design. This is not the case.
anon
@Neil, I'm airing the subject... It has never hurt to see what other developers think on a subject... :)
rozon
+2  A: 

I think this is a very generic question that is hard to answer. My best answer would be "It depends on your needs and the problem domain you are trying to solve".

klausbyskov
A: 

I like to keep things simple. In your Domain/Objects think of how you would speak about the object to determine what way to model it, would you say my car needs oil or my car's engine needs oil?

It depends on the domain. The Domain for a car factory would refer to cars differently than a car rental Domain.

I would have numberous window properties for each window and events off them, and a window state/position as well.

Burt
@Burt 9x out of 10 most folk would say "My car needs oil" even though in reality it is the engine. This isn't exactly wrong as in essence the engine makes up the car so you could simply resolve that problem by exposing a shortcut method, if you will, something like Car.FillOil which internally calls Engine.FillOil.
James
+2  A: 

In the scenario you have given I usually tend to think about it in a real life situation.

So the door is not private to the car i.e. the door of the car is publically accessible. The car does not open the door (unless it is a pretty cool car!) a User would open the door. Hence the door should probably be a public property of the car.

In terms of exposing the events, it really depends on whether you intend on handing them. For example, the OnLowOil event is probably an event you would want to be handled i.e. notify the user who would then perhaps do Car.Engine.FillOil

James
In regards of the door I find it hard to differenciate between the car and the door. The engine on the other hand; It probably has many sensors that could lead to a NeedService notification on the dashboard. Instead of wiring all the events for the engine, wouldn't it be better to let the car deal with them intrinsically and then issue a better (simpler) event to the user?
rozon
Well think about it, the door itself would have to become its own object as it is going to have properties such as Window/State(open/close) and its own methods like Open/Close. A good example of why would be my car, like many others, tells me that a door is open or not closed properly. So in that particular example how would you know if a door is closed if you have no Door object to check? In terms of the events, yes there would defo be situations where events from the engine are better not being exposed, but there will be events that you will need to expose, this is down to your own design.
James
A: 

There are no right or wrong models; there are models that are more or less useful for your specific purpose.

As others have said, think first on what information is relevant to your needs. And then discard the rest. That process of removing unnecessary detail is called abstraction. If we didn't perform abstraction, our models would be identical to the real-world entities that they represent! Which would be useless, since the ultimate goal of modelling is obtaining a simplified version of reality that allows us to reason about it in its absence.

CesarGon
+4  A: 

Einstein said "Make it as simple as possible, but no simpler."

Start with an empty object. As you develop the entire model, add to the object only those attributes that are NECESSARY.

John R. Strohm
And be prepared to refactor as you go. This means occasionally deciding that objects need to be split or merged for example.
Tony van der Peet
+6  A: 

Let us explore a little your example of opening the door of a car (say the front left). One could take several approaches (including those which you suggest):

  1. Car.OpenFrontLeftDoor
  2. Car.OpenDoor(FRONTLEFT)
  3. Car.Door(FRONTLEFT).Open
  4. Car.Part(DOOR_FRONTLEFT).Open
  5. Car.Part(DOOR_FRONTLEFT).DoAction(OPEN)

None of them is right or wrong, it depends on the situation. I am sure there are many more ways too.

Number 1 is very much a hard-coded function approach. This would be good for very simple, fixed situations. But it would become unmanageable if your model needs to accomodate variation.

Number 5 is taking a parameterised approach. The latter is a lot more flexible and requires a greater design nous to pull off but could be overkill for a simple problem.

Also bear in mind that your car object can present an external interface different to the internal implemenation. For example, you could use approach 5 internally but present an interface such as in 1, and translate the function calls under the hood (no pun intended).

Ultimately the ability to make decisions like this comes from experience. Expose yourself to good OO design, read books, examine the source code of good software. And above all, try different designs out and see for yourself what works and why.

invariant
+1 Nice breakdown.
Walter
I liked this breakdown.
rozon
A: 

I think there are several people here making the same point, but I will try again.

You are asking questions like should I or should I not expose "Door Opened" event. There is no answer to this question other than with another one: how are you going to use it

Ultimately the model is the means not the goal and as such the model cannot be defined outside the context. Even (especially) if you are building your model to sell it as a standalone product you have to think how your customers will use it which - again - is a discussion about context.

Trying answering such questions based one anything else (gut feel?) will be an exercise in counting demons on the end of the needle

mfeingold
A: 

If in doubt, consider the problem from a different approach: "How would I test these objects?" "How would I test the window?" "What would make testing easiest?" Being a lazy programmer, that's a very important question for me to answer. I want writing the tests to be dirt simple, yet highly effective in proving that my code works.

In your case, you have a car with doors that can open and close, and the doors have windows that can open and close, and they may or may not be electrically operated. How would you test the "window-down" function? Is the window's existence dependent upon the engine? Is it even dependent on the car, or is it really dependent only on the door? Do different doors have different shaped windows with different rules or different amounts of travel? Do different doors use identical electric motors to drive the windows, or are the window motors different for left-mounting versus right mounting?

And consider that a customer may give you a requirement that says "the windows only work when the engine is running", but is that really true? In most cars the windows work when the car's power switch is turned to "on". Put another way, is the window operation dependent on a spinning crankshaft in an engine, or is it actually dependent on 12 volts of electricity? So do you really need an engine instance in a car to test a window, or do you just need a battery?

Once you start asking those questions, you're likely to conclude that a power window is deserving of its own set of tests (up/down/part-way/full-travel/etc.), so it becomes a good candidate for being its own class. The number of different doors might be complex, so you figure a "door factory" might be an appropriate class to create that can manage all the different kinds of doors. Testing things in isolation is always easier: look at the harder questions about what the engine throttle setting should be to test the window-up function? What about the transmission gear, or the door open/close state? All these permutations make it hard to test, even though they have no bearing on whether the window works or not. So all these lead me to think the window classes should be tested standalone as much as possible. In the real world, you'd only need 12 volts to test a power window mounted in a door. So in your modeled world, you'd only need a mock or fake power supply object to provide the modeled power, not an engine object or a transmission gear. It's a simpler test.

After you take those sorts of ideas into consideration, you start realizing that passing dependencies in the tests (here's a power supply for the window test) makes them easy to test; thus the way to assemble the real components in your model would mean encapsulating construction in factories would make for the easiest way to create your car; so building the car might suggest the abstract factory pattern be used to inject all the dependencies into the car.

You might even start with a simple-but-brittle Car class with a hard coded Engine and hard coded Doors, and then refactoring it to add tests like those above. You would likely still end up with independent Car, Door, and Window objects, and an abstract factory pattern to create them all based on the model of car being built. This idea is called "emergent design."

John Deters