I have a quick question about the organization of a particular OOP problem.
Say I have a Terrain class, full of Tiles. There are multiple derivatives of class Tile, namely Door. The Door class has a method called open() which opens the door, and close() which closes the door. This makes perfect sense until both of these methods need to check for something in the way before opening and/or closing. How do I make a Door check for an object in the way without it knowing about its parent?
A simple solution would be to check for something in the way before calling open(), but if there was a different kind of door that needed to be check in a different shape, it creates clutter on the higher level.
It seems like this would have a simple answer, but it also seems like I run into this problem more often than not.
One answer is that Doors should know how to open and close themselves and know if they are blocked. If Door is a class, then both the state (is_open, is_blocked) and the behavior (open_the_door, close_the_door) should reside in the Door class. Encapsulation is a fundamental principle of the object-oriented paradigm.
But the real-world answer is usually more subtle. Can you provide some background on the application and what it needs to accomplish? There are clean, simple solutions that will work well for toy applications, but bigger apps are going to need something more sophisticated.
How to handle door is_blocked presents some design issues. There is no one right design, but there are good design and bad designs. Separating the good ideas from the bad ideas depends on more than just design principles-- it depends on the context of the problem.
If I had to take a guess, I'd guess that your application is a game. Maybe the tiles represent the area of the game board or map. You have identified that many different objects might have to interact and that it would be mess if they all referenced each other directly.
Games often have a master object called "Game" or "Board" or "Map". Let the master object hold the collection of things in the Tile hierarchy (tiles, doors, etc).
Let the master object also hold the collection of things that can block doors or otherwise interact with tiles and doors.
Now create a method named update() on the Tile class that accepts an object as a parameter.
And create a boolean attribute for the Door class called "blocked".
The update method for the Door might do something like this:
Door::update(BlockingObject object) {
if(object.location == this.location)
blocked = true
}
The method on the superclass of door might do nothing. Like this:Tile::update(BlockingObject obj) {
//tiles cannot be blocked
}
Now, inside the game loop, include a step where all the doors are set to blocked = false
.
The create some loops ask all of the tiles to check if they are blocked. It might look something like this in pseudo code:
For each tile {
For each blocking object {
tile.update(object)
}
}
This is a naive, but straight forward design that holds true to the OO paradigm.
The design gives tiles/doors and objects a chance to interact once per turn, without forcing them to hold references to one another.
The design will work fine for a few hundred tiles and objects, but it would become very slow for thousands of tiles.
Is it a good design?
The answer depends on the needs of the application.