I want to design a system where people use a house.
People in a house can walk around, sit in chairs, eat food, watch TV, cook, clean up, poo etc.
So I wanted to start off with the smallest room in the house. The toilets.
This is what I did.
So this doesn't look this bad right now, but I'm scared about adding another room to the equation.
The user shouldn't be allowed to poo() inside the kitchen for example. Nor can he flush() the living room.
So when he'll step in the kitchen or in the living room, he'll already have one or many methods which are of no use / will simply bug, that doesn't feel really efficient.
Am I right with this design ? How can I improve it ?
-
A user can only flush a toilet. Maybe the user needs more of a general +Action (toilet) and the toilet either has a default function like flush or you now have several things to choose from.JeffO– JeffO2017年05月05日 17:07:19 +00:00Commented May 5, 2017 at 17:07
-
I thought about that, but then the User can only do one action per room.Steve Chamaillard– Steve Chamaillard2017年05月05日 17:57:09 +00:00Commented May 5, 2017 at 17:57
4 Answers 4
The user shouldn't be allowed to poo() inside the kitchen for example. Nor can he flush() the living room.
Then it is a good indicator that those methods don't belong to the user but rather to the room.
However it is not clear how the objects will interact in your program. You should avoid any downcasting (from Room to Toilet) to access room specific actions. In this situation I think that you need an Action class. The Room should expose a method to provide a list of possible actions.
Action methods should be in the objects they related. So poo
and flush
method should be in the ToiletBowl
class.
With this approach you end up with objects which contains some actions(TV, Chair, ToiletBowl etc), rooms which contains those objects and house which contains rooms.
User will be able to step in different rooms, have access to the objects and execute their actions.
Room can contains different objects, you can easily put TV in the Toilet room and it can be used their bu user.
For example ToiletBowl
class will have two methods
Input(SomeStuff staff) {}
Flush() {}
-
Such a true and easy to understand answer. Thanks.Steve Chamaillard– Steve Chamaillard2017年05月07日 19:48:08 +00:00Commented May 7, 2017 at 19:48
Including methods in a base class that can't be implemented usefully in a subclass violates the Liskov Substitutability Principle, which is one of the most fundamental principles of object oriented design. The LSP essentially states that if code using an object of one type works correctly, it should also work with any subtype. In this case, however, you could write code that works with some types of room but not others.
As commented previously you could put the methods in the subtypes that they're appropriate for, but then you'd need to downcast to access them, which is generally considered a bad idea because it makes it difficult to add new behaviours that use the features of new types.
One solution to this is to use the Visitor pattern, which provides a useful way to access the various subtypes in a way that allowed you to be sure you have appropriately updated all operations that depend on this types.
A less involved approach may be to have Room expose a list of Command objects that can be applied to the room. This could be a useful approach of you want to provide a user interface that adapts to the available actions. But it doesn't provide any easy way of adapting for automatic algorithms that rely on those actions.
I think you need to re-architect your interface methods to make them less demanding and more informative. Instead of telling the room to flush
, inform it that you just when poo. The bathroom would respond by flushing, the bedroom would respond by stinking. Maybe your room metaphor really isn't the right comparison to your actual problem space.
The key here is to stop thinking about objects as inanimate things you do something to and start giving them agency. Ideal interfaces will have names like didLoad
, willAppear
or onClick
.
So if I saw a Room class for example in the context you are presenting, I would expect it to have methods on it like, didEnter
, willExit
, itemDeposited(item)
. The room will do the appropriate thing when I call these methods without me having to know what it does with them.