Currently I am designing a Monopoly game using Java.
Each player in the game can own different properties. The issue I'm having is how to assign different property objects to each player. I have both a Player class and a Properties class. Would composition be the best way to go about doing this? If so, how would I do it?
I would add a new class PropertyManager.
This allows you to easily provide business rules in a single location (good separation of concerns) rather than having to dive through a bunch of player or property objects if you opt for composition in either. This will keep the Player and or Property classes from becoming weighed down with buying/selling business rules in the future.
public final class PropertyManager {
/**
* The PropertyManager instance, example usage:
* PropertyManager.INSTANCE.buyProperty(property, buyer);
* NB: Good candidate for dependency injection instead if you are doing this.
*/
public static final PropertyManager INSTANCE = new PropertyManager();
private static final Map<Property, Player> propertyListing = new HashMap<Property, Player>();
/**
* Buy a property from the banker, banker or property manager could maintain
* Collection of available properties
*/
public void buyProperty(Player buyer, Property property) {
if (propertyListing.containsKey(property)) {
throw new IllegalStateException("Unable to buy unless owner sells it");
}
propertyListing.put(property, buyer);
}
/**
* Broker a transaction between two players for the sale of a property
*/
public void sellProperty(Player seller, Player buyer, Property property) {
if (!propertyListing.containsKey(property)) {
throw new IllegalStateException("Unable to sell Property which is not owned");
}
Player owner = propertyListing.get(property);
if (!owner.equals(seller)) {
throw new IllegalStateException("Unable to sell property seller doesn't own");
}
// TODO : Deduct/transfer monies (ensure sufficient value in buyer account etc)
propertyListing.put(property, buyer);
}
/**
* Retrieve a List of all of the Player's properties
*/
public List<Property> getProperties(Player owner) {
// TODO Either iterate through the propertyListing or use a second Map for player to List<Property>, NB: they should be guarded with a shared lock if you do this (threading).
}
/**
* Retrieve the owner of a Property or null if it is unowned
*/
#Nullable // javax annotation indiciates can be null
public Player getOwner(Property property) {
return propertyListing.get(property);
}
/**
* Hide the constructor as the only property manager should be INSTANCE
*/
private PropertyManager() {
// Prevent further instantiation
}
}
Think about it in real world terms.
When you're playing Monopoly and you purchase a property you take the property card and add it to your list of properties in front of you.
So in that case, you are a Player object adding Property objects to your property list.
public class Player
{
private List<Property> properties;
}
Composition works. As long as a player has a properties object, and the properties object contains all the necessary data, you should be fine (assuming you implement the necessary getter and setter methods).
the property can have an Owner property that is the Player.
You could also build a list on the Player of Properties.
You will need composition and polymorphism.
Assuming a player can have more than one property, you will need a List of properties. If Properties can differ in the attributes they have, you can apply Polymorphism and Inheritance. You will probably only see Inheritance below, but you will need Polymorphism when you are getting the different properties out and manipulating them.
In main:
public static void main(String args[]){
Player player1 = new Player();
BlackProperty blackProperty = new BlackProperty();
BlueProperty blueProperty = new BlueProperty();
player1.addProperty(blackProperty);
player1.addProperty(blueProperty);
}
All your domain classes:
public class Player{
private List<Properties> propertyList;
// getters and setters
public void addProperty(Properties properties){
if(this.propertyList == null){
this.propertyList = new ArrayList<Properties>();
}
this.propertyList.add(properties);
}
}
public class Properties{
private int noOfFloor;
// getters and setters
}
public class BlackProperty extend Properties{
private String noOfGate;
// getters and setters
}
public class BlueProperty extend Properties{
private String noOfLawn;
// getters and setters
}
Related
I have a question about subclasses and superclasses. In a project I'm working on, I have a superclass called "Team" and some subclasses called "TeamBlue","TeamRed"... Also, all of these subclasses have static fields and methods in them.
My question is: how do I store any subclass object (either TeamBlue or TeamRed) into a "Team" object? if this makes sense.
here is an example of what I'm trying to achieve:
Team team = new BlueTeam(); <-- storing any color team into a "team" object
this is a short version of the code I have:
class Team {
//empty class used for binding all the team classes
}
class BlueTeam extends Team {
public static List<String> players = new ArrayList<String>();
}
class PlayerData {
Team playerTeam;
public PlayerData(Team tm){
playerTeam = tm;
}
playerTeam.players // I want to access any subclass that is stored into this "myTeam" object and access its players list
}
class createData {
List<PlayerData> data = new ArrayList<PlayerData>();
// this is what I've tried but I get a null exception
Team team = new BlueTeam();
data.add(new PlayerData(team));
}
This is not object-oriented! Why does the blue team have a static list of players? Why is it public? You should use a getter and override the method.
abstract class Team {
// if there is a sensible default return then use it and the class needn't be abstract
abstract List<String> getPlayers();
}
class BlueTeam extends Team {
private final List<String> players = new ArrayList<>();
#Override
List<String> getPlayers() {
return players;
}
}
Usage:
Team team = new BlueTeam();
List<String> bluePlayers = team.getPlayers();
You're most likely doing class hierarchy wrong. Blue is not a property of a team, colour is. Meaning that instead of subclassing your Team for every possible colour, you should have a property called colour or name in Team and assign "blue" or "red" to that property in the instance of Team that represents the blue or red team.
I've been looking through some projects of games similar to the one I am developing and I've seen two ways of handling methods to mutate the Player.
Notes: a car, house, and job are the only three things to be handled. (only 3 items this game includes; - so a fourth item like family will never exist) However, this does not mean that no more fields will be added and mutated to the player class. (100+ more fields to be added)
Here is the generic java framework and usage (Which I am using at the moment):
#Data //lombok for setters/getters
public final class Player {
private final Car car = new Car();
private final Job job = new Job("none");
private final House hosue = new House();
public void makeHouseWooden() { //the method exists here in player class
house.setMode(wooden);
house.incrementTimesEdited(1);
house.refreshIfInside();
house.configureNewEnvironment();
}
}
This is what I've been seeing on other projects and would like to follow as the player class gets pretty big with methods:
#Data //lombok for setters/getters
public final class Player implements ContentWorker {
private final Car car = new Car();
private final Job job = new Job("none");
private final House hosue = new House();
#Override
public Player player() {
return this;
}
}
and the interface handles methods relating to the fields in Player.java
public interface ContentWorker {
Player player();
public default void makeHouseWooden() {
House house = player().getHouse();
house.setMode(wooden);
house.incrementTimesEdited(1);
house.refreshIfInside();
house.configureNewEnvironment();
}
}
I want to change to the second model because if I continue as I am at the moment then the Player class will become huge. (over 3000 lines)
This way I can keep the Player class for the fields only (better readability) and I could also have an interface which handles all house methods, another which handles all car methods and another which handles all job methods. (to avoid huge unreadable classes, also more dynamic interaction, easier to find the method you want)
public final class Player implements HouseWorker, CarWorker, JobWorker {
Which is better or more "efficient" and "easy to use" for my predicament?
I have the following case here:
Room { price; }
|
------
/ \
standard suite
I want to set price the of standard rooms in such a way that it remains static in all instances of standard and must not affect suite's price and vice versa. I have tried keeping price in Room class static and accessing it via getter and setter in child classes but it doesn't work. I also am reluctant to make price members in each child class because I don't like that solution. Maybe there's another beautiful OOP solution to it.
Having a separate static field in both the Room and Suite classes is the quickest/easiest solution.
Room
_________|_______
/ \
Standard Suite
| |
`static int price; `static int price;
Alternatively, you could create a static Map<Class<? extends Room>, Integer> in the Room class which stores the base price of each Room type.
public class Room {
private static Map<Class<? extends Room>, Integer> prices =
new HashMap<>();
public final int getRoomBasePrice() {
// If a Room subclass does not have a specific base price, return
// 1000 by default.
return Room.prices.getOrDefault(this.getClass(), 1000);
}
/** Sets the base price for the specified Room type.
*/
public final void setRoomBasePrice(int price) {
Room.prices.put(this.getClass(), price);
}
}
Using the above code will ensure the price stays constant across all instances of the class.
mySuite.setRoomBasePrice(2000);
(new Suite()).getRoomBasePrice(); // -> 2000
EDIT: After reconsideration, I realise that using static is not the correct method to solve the problem as it makes the code brittle and difficult to change.
The best method would be to have a separate RoomPriceService class, which provides a lookup for obtaining the price of a specific room type.
public class RoomPriceService {
private Map<Class<? extends RoomType>, Integer> prices;
public RoomPriceService(int defaultPrice) {
this.prices = new HashMap();
}
public void setPriceOfRoomType(Room r, Integer price) {
this.prices.set(r.getClass(), price);
}
public Integer getPriceOfRoomType(Room r) {
// You can expand on this code by adding setters/getters for
// setting and getting the default room price.
return this.prices.getOrDefault(r.getClass(), 100);
}
}
This way, you can have multiple RoomPriceService instances which can store prices for different circumstances (for example, you could have a RoomPriceService for each season, or a RoomPriceService for different sale promotions, etc).
Some background on the project: I am attempting to craft a space/sci-fi combat sim game with tabletop rpg style dice mechanics cranked up to 11 on the complexity scale, but still being transparent about the die rolls going on under the hood. I'm currently using the Star Wars Saga Edition combat rules as a basis.
Currently I'm trying to figure out a way to assign traits to vehicle.(possibly stored as a class for each vehicle) Each trait is an enum so that it can store multiple pieces of information. Here is the code I have for size categories:
public enum VehicleSize {
LARGE(1,"Speeder bike",5),HUGE(2,"Small Fighter",10),GARGANTUAN(5,"Tank, Medium Fighter",20),COLOSSAL(10,"Imperial Walker, Light Freighter",50),
COLLOSSALfrigate(10,"Corvette, Frigate",100),COLLOSSALcruiser(10,"Imperial-class Star Destroyer, Cruiser",200),
COLLOSSALstation(10,"The Death Star, Space Station",500);
private final int refMod;
private final int threshMod;
private final String desc;
VehicleSize(int reflexModifier,String example,int thresholdModifier)
{
refMod = reflexModifier;
desc = example;
threshMod = thresholdModifier;
}
public int getRefMod() {
return refMod;
}
public String getDesc() {
return desc;
}
public int getThreshMod() {
return threshMod;
}
}
My question is such: How do create vehicle profiles in such a way that I can assign this and similar enums as traits?
For practically all purposes, a field whose type is an enum class is no different than a field of any other object type, like Integer or String.
Create a private field, add a getter and setter, or if the field is final (likely in your case, because a vehicle instance can't change its type), add it as a constructor parameter and remo e the setter.
public class Vehicle {
private final VehicleSize vehicleSize;
// other fields
public Vehicle(VehicleSize vehicleSize) {
this.vehicleSize = vehicleSize;
}
public VehicleSize getVehicleSize() {
return vehicleSize;
}
// rest of class
}
There is nothing mysterious about an enum, other than the number of different instances of it are known at compile time (and a few more things, but nothing scary).
To add this into a class, you can use it like any user defined type.
public class MyClass {
private MyEnum myEnum;
}
I am trying to find a easy to extend way to create objects at runtime based on a static String class attribute, called NAME.
How can I improve this code, which uses a simple if construct?
public class FlowerFactory {
private final Garden g;
public FlowerFactory(Garden g) {
this.g = g;
}
public Flower createFlower(final String name) {
Flower result = null;
if (Rose.NAME.equals(name)) {
result = new Rose(g);
} else if (Oleander.NAME.equals(name)) {
result = new Oleander(g);
} else if ... { ... } ...
return result;
}
newInstance() can not be used on these classes, unless I remove the constructor argument. Should I build a map (Map) of all supported flower class references, and move the contructor argument to a property setter method, or are there other simple solutions?
Background information: my goal is to implement some kind of 'self-registering' of new Flower classes, by FlowerFactory.getInstance().register(this.NAME, this.class), which means that from the very good answers so far the introspection-based solutions would fit best.
One possibility would be using an enum. On the simplest level, you could replace constants like Rose.NAME with enum values, and maintain an internal mapping between enum values and classes to instantiate:
public enum Flowers {
ROSE(Rose.class),
OLEANDER(Oleander.class);
private final Class<? extends Flower> flowerClass;
Flowers(Class<? extends Flower> flowerClass) {
this.flowerClass = flowerClass;
}
public Flower getFlower() {
Flower flower = null;
try {
flower = flowerClass.newInstance();
} catch (InstantiationException e) {
// This should not happen
assert false;
} catch (IllegalAccessException e) {
// This should not happen
assert false;
}
return flower;
}
}
Since the flower classes classes have no default constructor, Class.newInstance() can not be used, so instantiating the class via reflection is a bit more cumbersome (although possible). An alternative could be to use a Prototype to create the new flower instance.
This already ensures that you always keep the mapping between possible flower names and actual flower classes in sync. When you add a new flower class, you must create a new enum value, which includes the mapping to create new class instances. However, the problem with the enum aproach is that the Garden instance you use is fixed at startup. (Unless you pass it as a parameter to getFlower() - but then there is a risk of losing coherence, i.e. it is harder to ensure that a specific group of flowers is created in a specific garden).
If you want to be even more flexible, you may consider using Spring to move the whole mapping between names and concrete (bean) classes out to a configuration file. Your factory then simply loads a Spring ApplicationContext in the background and uses the mapping defined in it. Whenever you introduce a new flower subclass, you just need to add a new line to the config file. Again, though, this approach, in its simplest form, requires you to fix the Garden bean instance at configuration time.
If you want to switch between different gardens at runtime, and ensure consistency between gardens and groups of flowers, a Factory using an internal map of names to flower classes may be the best choice. Whereas the mapping itself can again be stored in configuration, but you can instantiate distinct factory instances with distinct Garden instances at runtime.
You can use reflection despite having a constructor argument:
Rose.class.getConstructor(Garden.class).newInstance(g);
Combined with a static name to class mapping, this could be implemented like this:
// TODO handle unknown name
FLOWERS.get(name).getConstructor(Garden.class).newInstance(g);
where flowers could be populated in a static initializer block:
static {
Map<String, Class<? extends Flower>> map = new HashMap<String, Class<? extends Flower>>();
map.put(Rose.NAME, Rose.class);
// add all flowers
FLOWERS = Collections.unmodifieableMap(map);
}
You could use an enum with a abstract factory method:
public enum FlowerType{
ROSE("rose"){
public Rose createFlower(Garden g){
return new Rose(g);
}
},
OLEANDER("oleander"){
public Oleander createFlower(Garden g){
return new Oleander(g);
}
};
private final static Map<String, FlowerType> flowerTypes = new HashMap<String, FlowerType>();
static {
for (FlowerType flowerType : values()){
flowerTypes.put(flowerType.getName(), flowerType);
}
private final String name;
protected FlowerType(String name){
this.name = name;
}
public String getName(){
return name;
}
public abstract Flower createFlower(Garden g);
public static FlowerType getFlower(String name){
return flowerTypes.get(name);
}
}
I cannot say if this is the best way in your case, though, as I have to few information.
Apart from using an enum, or a mapping you could use reflection if there is a simple mapping of name to class.
public Flower createFlower(final String name) {
try {
Class clazz = Class.forName("mypackage.flowers."+name);
Constructor con = clazz.getConstructor(Garden.class);
return (Flower) con.newInstance(g);
} catch (many exceptions) {
throw new cannot create flower exception.
}
}
You could also do it by storing the string names in a map to avoid the series of if/elses.
Map<String, Class> map;
map.get(name).newInstance();
If you have full control over your classes you can perform instantiation using reflection directly from the string name, e.g.,
Class.forName(name);
Apart from this you could also try a dependency injection framework. Some of these provides the capability to retrieve an object instance from a string name.
If all your Flowers have the same constructor signature you could use reflection to set the parameter on the constructor.
Obviously this is getting into the realms of dependency injection, but maybe that's what you're doing :)
If you have lots of different parameters in your constructor, if it is safe to do so, you could the type of each parameter to look up the instance to pass in, a bit like what Guice does.
I would suggest removing the state from your factory object and pass your Garden object as an argument in the static factory method:
public class FlowerFactory {
private FlowerFactory() {}
public static Flower createFlower(final String name, Garden g) {
Flower result = null;
if (Rose.NAME.equals(name)) {
result = new Rose(g);
} else if (Oleander.NAME.equals(name)) {
result = new Oleander(g);
} else if ... { ... } ...
return result;
}