I've been thinking about this object oriented design question for a while now and have unable to come up with a satisfactory solution, so thought I'd throw it open to the crowds here for some opinions.
I have a Game class that represents a turn based board game, we can assume it's similar to Monopoly for the purposes of this question. In my design I have a Player class containing a method TakeTurn.
The Game loops through all Players and calls the TakeTurn method to do all the necessary things to complete the turn. I want to be able to have n number of players, and be able to set an arbitrary number of them to be computer players. So, my thought was to have a HumanPlayer class and a ComputerPlayer class, both of which derive from Player.
The Game knows only the Player class and simply calls the TakeTurn method on each Player in turn. My problem comes in the fact that ComputerPlayer objects can be completely automated, i.e. keeping with the Monopoly example, can decide to buy a property using some piece of logic. Now, with the HumanPlayer object, it needs to get an input from the actual user to be able to buy a property for instance, which seems to imply a different interface and potentially mean they shouldn't derive
I haven't been able to come up with a good solution to the problem without having the Game class know the actual implementations of the various Player classes explicitly. I could always make the assumption in the Game class that there will only ever be human and computer players and effectively close it for extension, but it doesn't seem like good OO programming.
Any opinions on this would be appreciated.
The Open-Close principle (OCP) is the O in the well known SOLID acronym. A module will be said to be open if it is still available for extension. For example, it should be possible to add fields to the data structures it contains, or new elements to the set of functions it performs.
Existing code should be modified only for bug fixing. New classes can reuse existing code via inheritance. Open/closed principle is intended to mitigate risk when introducing new functionality. Since you don't modify existing code you can be assured that it wouldn't be broken.
In object-oriented programming, the open–closed principle states "software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification"; that is, such an entity can allow its behaviour to be extended without modifying its source code.
I think you should not let the Game class handle IO. this way, the (blocking) TakeTurn method will hide from the game board the means of implementation. it can use other objects to communicate with the user.
All the Game class should concern itself with is the state of the board and the turn. the players should all implement a single Player interface, and hide all implementation from the Game.
If the Game is managing the game state and doing I/O, the Game is doing too much.
You want Game to be tightly focused on just rules and turns and state changes. Game doesn't know what a player is; it only knows that it has players.
You want Players to examine the Game state and execute the legal actions during their turns.
Human Players and the Game as a whole both share a common I/O package that shows game state and prompts humans for their input.
You can make good use of the Java Observable
by making the I/O package an Observer
of the Game. That way, Game state changes are reported to the I/O for display or logging or both.
I would probably not have two HumanPlayer
and ComputerPlayer
classes, but a single Player
class which is configured at creation time with the proper input strategy.
The way the player obtains information to decide its move in the next turn of the game is the only thing that varies (from the original problem description, at least), so just encapsulate that in a separate abstraction.
Whatever high-level class that sets up the game should also create the two sets of players (one human, another computer-simulated), with the proper input strategy for each, and then simply give these player objects to the game object. The Game class will then only call the TakeTurn
method on the given list of players, for each new turn.
Instead of telling the game class there is only ever one human, why not let it get that input during the menu/initialization of the game? If there are more players, that can be decided via some form of input (select players in the menu), prior to the game class initialization.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With