Creating a player class that can be used by two different games - java

I have to write some classes for snakes and ladders and tic tac toe.
I am trying to create a Player class which is the super class of Player_Piece and Player_Symbol.
Player class has to: Create the player objects, stores the player object states:Name,Score.
Player_Piece has to assign the color and position to the objects which is the player piece on the game board of snakes and ladders. It also has to move the pieces
Player_Symbol is the class for the tic tac toe game it assigns and holds the players symbol, (either a nought or a cross) and positions.
I am not sure if I have done these classes correctly and I would appreciate some advice on anything I should change. I am very new to java and I have been thrown into the deep end with this
Player Class
public class Player {
private String PlayerName;
public Player(String name) {
PlayerName = name;
}
/**
* This set method sets the name of the player.
*
* #param Takes in a String as name.
*/
public void setName(String name) {
this.PlayerName = name;
}
/**
* This get method returns the String value of player name.
*
* #return PlayerName, a String value.
*/
public String getName() {
return PlayerName;
}
}
Player_Piece Class
public class Player_Piece extends Player {
// class constants
// Colors for the players piece
public static final String BLUE = "Blue";
public static final String RED = "red";
public static final String YELLOW = "Yellow";
public static final String BLACK = "Black";
// Types for each players piece.
public static final String PLAYER1PIECE = "player one's piece";
public static final String PLAYER2PIECE = "player two's piece";
public static final String PLAYER3PIECE = "player three's piece";
public static final String PLAYER4PIECE = "player four's piece";
// fields
private String color;
private String type;
private int row;
private int column;
// constructors
/**
* Constructs a new player piece with a colour and type at the given position.
* #param color The piece's color must be one of the following: BLUE, RED, YELLOW or BLACK.
* #param type The piece's type must either PLAYER1PIECE, PLAYER2PIECE, PLAYER3PIECE, PLAYER4PIECE.
*/
public Player_Piece(String color, String type, int row, int column) {
this.color = color;
this.type = type;
this.row = row;
this.column = column;
}
// methods for the class
/**
* Returns this players piece color.
* #return the color; either BLUE, RED, YELLOW or BLACK.
*/
public String getColor() {
return this.color;
}
/**
* Returns this player piece's type.
* #return the type; either PLAYER1PIECE, PLAYER2PIECE, PLAYER3PIECE, PLAYER4PIECE.
*/
public String getType() {
return this.type;
}
/**
* Returns this player's piece row position.
* #return the position of the piece.
*/
public int getRow() {
return this.row;
}
/**
* Returns this player's piece column position.
* #return the position of the piece at the column
*/
public int getColumn() {
return this.column;
}
/**
* Returns a String of this piece.
* #return a three letter String, such as "P1P" for player one's piece.
*/
public String toString() {
return this.type.substring(0, 1);
}
/**
* Moves the piece to the position.
*
* #param row The row position for the piece to move to.
* #param column The column position for the piece to move to.
*/
public void move(int row, int column) {
this.row = row;
this.column = column;
}
}
Player_Symbol Class
public class Player_Symbol extends player {
private String symbolChoice;
private int[][] symbolPosition;
public void setSymbol (String symbol) {
this.symbolChoice = symbol;
}
public void setSymbolPos(int[][] position) {
this.symbolPosition = position;
}
public String getSymbol() {
return symbolChoice;
}
public int[][] getSymbolPos() {
return symbolPosition;
}
}

I don't know what do you expect from our answers. But if you wanna know how to create good structure of your app. There are some points related to Java.
Inheritance is not so good pattern. If you have really many same attributes use it. It is rather useful for extending some existing components.
What is important and useful is interface. For example you need methods getName, getScore, saveState etc. You create interface with these methods and then implemet it in your classes.
Encapsulation is also important, your attributes should be private if not necessary to be protected or public.
OOP - Use static attributes and methods only if it is good in that situation. For example library of math operations or logging.
MVC (Model View Controller) - You should separate logic, user interface and collecting user actions.
You can also look at some patterns like singleton or decorators.
You wrote you are new to Java so I hope you understand it.
In future your app could have structure like this:
Entity classes mapped from your database tables
DAO classes for accessing database (CRUD operations)
Service classes contaning main logic of your app
Controller classes that should colletct actions
from user and validate data.
UI - user interface, it depends if it is web app(jsp, jstl, jsf) or desktop app (swing, fx)
Of course there are many alternatives, that depends on your requirements and technology.

The inheritance is not a good idea. Player_Piece extends Player implies 'a player's piece is a player', in other words 'a pawn is a human'. The fact that this is not a good representation of the real world is not even the worst part; my biggest concern is the fact that you are introducing 'code smell'.
The subclasses combine multiple responsibilities: name and position. This may sound like a total non-issue since the two responsibilities are so small. What harm is there in combining the two? Well, in my experience, every maintenance nightmare started out small. Refactor while it is still easy to do so; the longer you wait, the bigger the pain. In general, it is a violation of the single responsibility principle. For this specific case, here's why this is bad.
Lifetime
Name and position are likely to have different lifetime. Position only has meaning for the duration of a single game, whereas name could persist across multiple games. This is typically a sign that there should be two different objects.
Reusability
Position is not only relevant for the player, but also for the snakes and the ladders. Right now, position is implemented in class Player_Piece by two integer properties row and column. Move these properties to a separate class Position and you will soon find that the snakes and the ladders benefit from this class too. If you don't, then you'll soon find some code duplication creeping in; obj1.row == obj2.row && obj1.column == obj2.column will become a recurring expression in your code. With the proper abstractions, this can be reduced to the more readable obj1 == obj2.
Talking of abstractions, please stop using strings for colors, types and symbols; enums are more appropriate.

Related

Referencing method from abstract class

START OF INSTRUCTIONS
If there is a game piece on the clicked square (clickedSquare.getPiece()!= null)
Make sure the game piece belongs to the current player. You can get the owning player by calling the getPlayerType() method on the AbstractGamePiece returned by getPiece(). You can then compare that to the currentPlayerTurn JailBreak class member.
If the piece on the clicked square belongs to the current player
Set the selected square equal to the clicked square
Call the select() method on the selected square to show the yellow border
END OF INSTRUCTIONS
I've figured out how to highlight the piece by implementing the select() method, butt
I've tried several different implementations, such as AbstractGamePiece.getPlayerType()==currentPlayerTurn, using nested if statements to set conditions on clickedSquare.getPiece(), and a couple others that I can't think of off the top. I can't seem to get a reference to getPlayerType() from the abstract class. There is pre-written code in the class that seems to work fine as far as accessing the AbstractGamePiece, such as
private void changePlayerTurn()
{
if (currentPlayerTurn == AbstractGamePiece.PLAYER_OUTLAWS)
currentPlayerTurn = AbstractGamePiece.PLAYER_POSSE;
else
currentPlayerTurn = AbstractGamePiece.PLAYER_OUTLAWS;
}
I feel like I'm going about this wrong, but I can't seem to get a reference to the getPlayerType(). The one time I did, I created a new object of the abstract class, but the constructor needs 3 parameters that aren't really appropriate here.
Supporting code:
abstract public class AbstractGamePiece
{
// All class members are provided as part of the activity starter!
// These two constants define the Outlaws and Posse teams
static public final int PLAYER_OUTLAWS = 0;
static public final int PLAYER_POSSE = 1;
// These variables hold the piece's column and row index
protected int myCol;
protected int myRow;
// This variable indicates which team the piece belongs to
protected int myPlayerType;
// These two strings contain the piece's full name and first letter abbreviation
private String myAbbreviation;
private String myName;
// All derived classes will need to implement this method
abstract public boolean hasEscaped();
// The student should complete this constructor by initializing the member
// variables with the provided data.
public AbstractGamePiece(String name, String abbreviation, int playerType)
{
myName = name;
myAbbreviation = abbreviation;
myPlayerType = playerType;
}
public int getPlayerType()
{
return myPlayerType;
}
public void setPosition (int row, int col)
{
myRow = row;
myCol = col;
}
public int getRow()
{
return myRow;
}
public int getCol()
{
return myCol;
}
public String getAbbreviation()
{
return myAbbreviation;
}
public String toString()
{
return (myName + " at " + "(" + myRow + "," + myCol + ")");
}
public boolean canMoveToLocation(List<GameSquare> path)
{
return false;
}
public boolean isCaptured(GameBoard gameBoard)
{
return false;
}
Code that highlights the pieces indiscriminately has been implemented successfully.
private void handleClickedSquare(GameSquare clickedSquare)
{
if (selectedSquare == null)
{
selectedSquare=clickedSquare;
selectedSquare.select();
}
else if (selectedSquare == clickedSquare)
{
selectedSquare.deselect();
selectedSquare = null;
}
else
{
}
Why is it that I'm unable to create a reference to the getPlayerType() method?
Just call getPlayerType on any expression of type X, where X is either AbstractGamePiece or any subclass thereof. For example, square.getPiece().getPlayerType().
Method references are a thing in java and are definitely not what you want, you're using words ('I'm unable to create a reference to getPlayerType') that mean something else. A method reference looks like AbstractGamePiece::getPlayerType, and let you ship the concept of invoking that method around to other code (for example, you could make a method that calls some code 10 times in a row - so this method takes, as argument, 'some code' - and method references are a way to that). It is not what you want here, you want to just invoke that method. Which is done with ref.getPlayerType() where ref is an expression whose type is compatible with AbstractGamePiece. From context, clickedSquare.getPiece() is that expression.

Creating boats in battleship game

I am creating a battleship game in one of my classes. I am having trouble on creating the "PTBoat" and placing it on the screen. I have a 10x10 board and need help creating an initializing the boats. The size of the PTBoat needs to be 2 spots on the board. I think I have the random direction, column, and row figured out but am stuck on how to call it in the board class. The first portion is the PTBoat class and the second half of code is the Board Class. The main method has been fully written for me so I did not include that.
/**
* Class for the PT Boat of the Battleship Game.
* Superclass: Ship
* Subclasses: none
* Attributes: String name
* int charges;
* name = "PT Boat"
* size = 2
* charges - number of depth charges on this PT Boat
* You must declare the attributes, complete the constructors and
* write any necessary getters and setters
*/
public class PTBoat extends Ship
{
// instance variables
public String PTBoat;
public int charges = 2;
public int size = 2;
/**
* Constructors for objects of class Carrier
*/
public PTBoat(String name, int size)
{
}
public PTBoat(int row, int col, int dir)
{
row = (int)(Math.random() * 10 + 1);
col = (int)(Math.random() * 10 + 1);
dir = (int)(Math.random() * 2 + 1);
}
}
/**
* Board class for the Battleship game.
*
* A board is an nxn array containing one each of: Carrier
* Battleship
* Destroyer
* Submarine
* PTBoat
*/
import java.util.Scanner;
public class Board
{
// class variables
// If the number of ships is changed, the constructor must be
// updated as well
// When debug is true, positions of ships will be shown when the
// board is displayed. This is helpful when testing the game since
// you won't have to guess the ships' locations.
final static boolean debug = true;
final static int board_size = 10;
final static int num_ships = 5;
// Characters printed when the board is displayed. Not all are used.
final static char hit = 'H';
final static char miss = 'M';
final static char used = 'S';
final static char blank = ' ';
final static char sunk = 'X';
// instance variables - replace the example below with your own
private char[][] board = new char[board_size][board_size];
private int num_sunk;
private Ship[] ships = new Ship[num_ships];
private Scanner scanIn;
/**
* Default constructor for objects of class Board
*/
public Board(Scanner s)
{
// initialise instance variables
scanIn = s;
num_sunk = 0;
initializeBoard();
// create the ships
ships[0] = new PTBoat();
hideShip(0);
ships[1] = new Submarine();
hideShip(1);
ships[2] = new Destroyer();
hideShip(2);
ships[3] = new Battleship();
hideShip(3);
ships[4] = new Carrier();
hideShip(4);
}
You have some misconceptions for the class PTBoat, let's start with a few:
One of the attributes should be the name of the ship, in this case, "PT Boat", but you defined this:
public String PTBoat;
So your variable is named PTBoat, the same that the class which is wrong. It should be named "name", like this:
public String name;
The first constructor has two arguments so when called it will be used to give values to the related attributes, like this:
public PTBoat(String name, int size)
{
this.name = name;
this.size = size;
}
The second constructor looks like it's intended to set up the attributes row, col and dir, that you should define in the class. With your code you are reassigning the value of the variables that you receive, which is useless. Later when you instantiate the ship from the Board you should use one of the constructors like this:
ships[0] = new PTBoat("MyAwesomePTBoat", 2);
In your instructions is also mentioned that you need to create getters and setters, so your variables look like they should be private, not public. A getter is a simple method that returns the value of the variable, a setter is used to set the value to a value given. Those methods are public so they can be called from outside the class where they are defined.
Anyway, I would recommend you have a look at any basic Java tutorial to understand better all those concepts.

Use of static classes to represent different forms of currency

I coded myself an issue last night while developing a small game. The other day, I convinced myself that I should devote some of my spare time to something productive, so instead of gaming I decided I would start working on a text-based rpg. I came, then, to the issue of representing currency in game. Now, because this is just for fun, I'd like to challenge myself a bit. Instead of just representing currency as a single value ( eg: a single type of coin called "gold piece" isn't the only kind of coin in the game .)
What I decided to do was create 4 types of coin - pence, copper, denar, and oren. All 4 of the coins have values such as weight, volume, material, and name. Furthermore, the coins have exchange rates, which determine their relative values. The point of this was to permit different usages of what would otherwise be a boring old currency. My issue is that I am unsure how to implement it.
What I arrived at last night was 4 classes ( Pence, Copper, Denar, Oren, ) extending an abstract class Coin. Coin contains a lot of protected static elements, such as DENSITY, VOLUME, NAME, EXCHANGE for all 4 subclasses.
The constructors for the sub-classes look like this:
public Coppers() {
super();
super.metal = COPPER_METAL;
super.name = COPPER;
super.setVolume();
super.setDensity();
super.setWeight();
}
And the methods in the super class look like this:
protected void setDensity() {
switch( getMetal()) {
case "copper":
this.density = DENSITY_COPPER;
break;
case "silver":
this.density = DENSITY_SILVER;
break;
case "gold":
this.density = DENSITY_GOLD;
break;
default:
this.density = DENSITY_COPPER;
break;
};
}
This seems terribly... wrong. I'm not sure what the best practice would be. I asked my friends about using a static class to hold these values, and received mixed responses. The POINT of these classes though, is important. Imagine the player class has an object called Purse, which keeps track of the number of different types of coins. With their Purse, the player can exchange coins at banks, purchase goods, and sell goods for coins. It wouldn't make any sense to hold a Set of all instantiated coins, right? I just need the information, and the methods. Does implementing a static class make sense, then? How can I get all 4 coins working best, when they all share so many properties?
What you may do in this case is to use an Enum. You enumerate the constants you need, give them a type through their constructors.
Now that we have their type, we can compare it to the string you're handling within your code, if none of the types match, we set it to Density.COPPER by default.
Density density;
protected void setDensity (String metal) {
for (Density d : Density.values()) {
if (metal.equals(d.getType())) {
this.density = d;
return;
}
}
this.density = Density.COPPER;
}
enum Density {
COPPER("copper"),
SILVER("silver"),
GOLD("gold");
String type;
Density(String s) {
type = s;
}
public String getType() {
return type;
}
}
Let's work backwards here.
Imagine the player class has an object called Purse, which keeps track of the number of different types of coins. With their Purse, the player can exchange coins at banks, purchase goods, and sell goods for coins.
What this implies:
public class Purse {
private final List<Coin> coins = new ArrayList<>();
}
This tells me that enums are not sufficient (enough) here. An enum in this context describes multiple states; what you're looking for are actual objects which can hold values that you need to do some calculations on.
If our intention is to hold on to this currency, I don't see anything wrong with some central object to describe it.
In my mind, using an abstract class for this is probably fine, but you're missing a critical component: a factory to create the type of coin you want. You'll also want to reduce the responsibilities of the coin altogether - it's fine for a coin to know its value, but it shouldn't care what its value is relative to other coins; that's the responsibility of some kind of exchange object which intends to produce a number of coins based on the value of your given coin.
So let's write the constructor for the abstract class. If we're thinking of creating a generic coin, we need to know its volume, density, and weight. The name is provided by virtue of its class name, so you really shouldn't need to worry about that; you can extract it later.
If you want some sort of coin hierarchy, you can leverage Comparable; state the ordering there instead of through enumeration.
public abstract class Coin implements Comparable<Coin> {
protected final int volume;
protected final int density;
protected final int weight;
public Coin(int volume, int density, int weight) {
this.volume = volume;
this.density = density;
this.weight = weight;
}
public int getVolume() {
return volume;
}
public int getDensity() {
return density;
}
public int getWeight() {
return weight;
}
}
This describes the barebones Coin type.
For an example, let's describe the Copper type here as well. This code makes the assumption that coin of the same type is comparable otherwise it demotes itself (with Copper being at the bottom of the list).
Observe a few things:
We preserve a lot of the original logic from the parent class
We override compareTo (because we must), and we let that drive the chief way of ordering on coins.
This does not describe any sort of conversion since the coins really shouldn't need to know about that. They have no value between coins until it's time to actually convert them. Think foreign exchange.
public class Copper extends Coin {
public Copper(final int volume, final int density, final int weight) {
super(volume, density, weight);
}
#Override
public int compareTo(final Coin otherCoin) {
if(otherCoin instanceof Copper) {
return (volume - getVolume()) + (density - getDensity()) + (weight - getWeight());
}
// assume Coppers are worth the least
return Integer.MIN_VALUE;
}
}
The other currencies are left as an exercise for the reader.
The last thing I want to cover is some form of generator for all of your currencies. This is where a bit of reflection magic can really help to invoke the constructor you care about.
I've also made this return an Optional<T extends Coin> so that, in the event the generation fails for some reason, you have an optional to work with instead of null.
public class CoinFactory {
private CoinFactory() {
}
public static <T extends Coin> Optional<T> generateCoin(int weight, int volume, int density, Class<T> clazz) {
Optional<T> coin = Optional.empty();
try {
coin = Optional.of(clazz.getDeclaredConstructor(int.class, int.class, int.class)
.newInstance(weight, volume, density));
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
e.printStackTrace();
}
return coin;
}
}
You can use this main method to smoke test it:
public static void main(String[] args) {
final Optional<Copper> x = CoinFactory.generateCoin(10, 20, 30, Copper.class);
if(x.isPresent()) {
System.out.println(x.get());
}
}
Put a private Map in Coin for Density, with keys being "copper", "gold", and "silver", and the values being the DENSITY_ constants. setDensity() should simply run:
this.density = densityMap.get(getMetal());
Or better yet, scrap setDensity(), and instead simply have getDensity(), which returns densityMap.get(getMetal()).
Since the four kinds of coin don’t differ in behavior, one class is enough. I suggest this:
public enum Coin {
PENCE, COPPER, DENAR, OREN;
private static final String[] METAL = { "copper", "copper", "silver", "gold" };
private static final int[] VALUE = { 1, 12, 60, 360 };
public String getMetal() {
return METAL[ordinal()];
}
public int getValue() {
return VALUE[ordinal()];
}
}

Computer Science FRQ

(EDITED CODE)
I am having a bit of an issue I hope I can get some help on. Here are my conditions:
You are developing a program to keep track of team standings in a league. When a game is played, the winning team (the team with the higher score) gets 2 points and the losing team gets no points. If there is a tie, both teams get 1 point. The order of the standings must be adjusted whenever the results of a game between two teams are reported. The following class records the results of one game.
public class GameResult
{
public String homeTeam() // name of home team
{ /* code not shown */ }
public String awayTeam() // name of away team
{ /* code not shown */ }
public int homeScore() // score for home team
{ /* code not shown */ }
public int awayScore() // score for away team
{ /* code not shown */ }
// instance variables, constructors, and other methods not shown
}
The information for each team is stored by an instance of the class TeamInfo whose partial definition is below.
public class TeamInfo
{
public String teamName()
{ /* code not shown */ }
public void increasePoints(int points)
{ /* code not shown */ }
public int points()
{ /* code not shown */ }
// instance variables, constructors, and other methods not shown
}
The class TeamStandings stores information on the team standings. A partial declaration is shown below.
public class TeamStandings
{
TeamInfo[] standings; // maintained in decreasing order by points,
// teams with equal points can be in any order
public void recordGameResult(GameResult result)
{ /* to be completed as part (c) */ }
private int teamIndex(String name)
{ /* to be completed as part (a) */ }
private void adjust(int index, int points)
{ /* to be completed as part (B)/> */ }
// constructors and other methods not shown
}
And here is the actual question:
Write the method adjust. The method adjust should increment the team points for the team found at the index position in standings by the amount given by the parameter points. In addition, the position of the team found at index in standings should be changed to maintain standings in decreasing order by points; teams for which points are equal can appear in any order.
And here is what I have so far:
private void adjust(int index, int points)
{
int Score[] = new int[standings.length]
for ( int i=0; i < standings.length; i++)
{
Score[i] = points;
Arrays.sort(Score);
}
}
I realize this is very wrong and need a little guidance to solve this. Thank you!
Something like this should work:
private void adjust(int index, int points) {
// increase points of winning team
TeamInfo curr = standings[index];
curr.increasePoints(points);
// get the new score of the winning team
int points = curr.points();
// perform an insertion sort on the modified portion
int i = index;
while (i > 0 && standings[i-1].points() < points) {
// shift teams with lower scores rightwards
standings[i] = standings[i-1];
i--;
}
standings[i] = curr;
}
Basically, it just gets the winning team (curr) at the specified index parameter and increments its points. Since the list must be ordered by team points in descending order, just insert the team in their correct position after adjusting the points.
problem is :
for ( int i=0; i <= standings.length; i++)//here index out of bounds
{
Score[i] = index, points;//here
}
write like :
for ( int i=0; i <standings.length; i++)
{
Score[i] = points;
}
Here's how to adjust the points for a team in the standings.
private void adjust(int index, int points)
{
/* 'index' is by definition an index into the standings array
* 'points' is by definition how many points to give to the team at 'index'
* each TeamInfo object has a method called increasePoints()
* therefore, to increase the number of points for a team in the standings... */
standings[index].increasePoints(points);
}
make sense?
Now, to sort the standings in order of point value, I imagine the exercise wants you to do something that uses TeamStandings.teamIndex() in combination with the other methods in your TeamInfo class. But since the code is either hidden or not written yet, I can't do much more.

What is the Java standard for object cohesion? Does too much information in an object mean bad design? - see example

I'm creating a project which models an airport landing system. I have a plane object which stores all the information I need to sort the plane into a queue and store in a database. All the vital information is included in the object but I have also included the co-ordinates for each plane. My issue is that it may not be considered cohesive because each plane does a lot of different things.
I just want to know if this is considered bad design or is there a better way to do this?
Also, what is the "rule" for cohesion inside of objects? is there a specific design pattern that can maybe deal with this?
public class Plane extends Aircraft {
/*
* Flight status should only take one of these enum values
*/
private static enum Status {
REGISTERED, IN_QUEUE, LANDING, LANDED
};
// Set aircraft status to REGISTERED when created
private Status status = Status.REGISTERED;
private double fuelLevelPercentage;
private int passengerCount;
private int aircraftNumber;
private String airlineCompany;
private String departureAirport;
// This is used by the constructor to assign a random city to each new Aircraft
private final String[] cities = { "Rome", "Berlin", "Heathrow",
"Edinburgh", "Cardiff", "Dublin", "Stansted" };
// Used to set airline companies
private final String[] airLineCompanies = { "Easyjet", "Ryanair",
"British Airways","Flybe","Air Lingus", "Virgin" };
// Random number generator used by the constructor
private Random rand;
// Thread for this instance of Aircraft
private Thread aircraftThread;
// Radius of path when flying in circle (km?)
private final double FLIGHT_RADIUS = 10;
// Time taken to complete one complete loop (ms)
private final double FLIGHT_PERIOD = 120000;
// Angular frequency omega (rad/s)
private double OMEGA = 2 * Math.PI / FLIGHT_PERIOD;
// Time taken between being directed to land, and landing (ms)
private int TIME_TAKEN_TO_LAND = 30000;
// Time take to use one percent of fuel (ms)
private double time_taken_to_use_one_percent_of_fuel = 30000;
// variable to keep track of time since instantiated (ms)
private int time = 0;
// The aircraft Thread sleeps for TIME_STEP between updating
private final int TIME_STEP = 20;
private int time_when_called_to_land;
private int hour_of_arrival;
private int minute_of_arrival;
/*
* Set coordinates at time zero
*/
private double x_coord = 0;
private double y_coord = FLIGHT_RADIUS;
private double altitude = 1000;
/*
* Used to calculate path to airport
*/
private double x_coord_when_called;
private double y_coord_when_called;
private double altitude_when_called;
Calendar calendar = Calendar.getInstance();
/**
* This constructor sets the following fields to random values Dummy Data -
* should have a better way to do this
*/
public Plane() {
rand = new Random();
this.fuelLevelPercentage = rand.nextInt(100);
this.departureAirport = cities[rand.nextInt(cities.length)];
this.passengerCount = rand.nextInt(500);
this.aircraftNumber = rand.nextInt(50000000);
this.airlineCompany = airLineCompanies[rand.nextInt(airLineCompanies.length)];
}
/**
* this fly method will call on a different method depending on the status
* of the Aircraft
*/
public void fly() {
if (status == Status.REGISTERED) {
useFuel();
} else if (status == Status.IN_QUEUE) {
flyInCircle();
useFuel();
} else if (status == Status.LANDING) {
flyToAirport();
useFuel();
} else if (status == Status.LANDED) {
}
}
public void flyInCircle() {
x_coord = FLIGHT_RADIUS * (Math.cos(OMEGA * (time)));
y_coord = FLIGHT_RADIUS * (Math.sin(OMEGA * (time)));
}
public void flyToAirport() {
if (!(x_coord < 1 && x_coord > -1 && y_coord < 1 && y_coord > -1
&& altitude < 1 && altitude > -1)) {
x_coord -= x_coord_when_called * TIME_STEP / TIME_TAKEN_TO_LAND;
y_coord -= y_coord_when_called * TIME_STEP / TIME_TAKEN_TO_LAND;
altitude -= altitude_when_called * TIME_STEP / TIME_TAKEN_TO_LAND;
} else {
System.out.println("Aircraft landed");
status = Status.LANDED;
hour_of_arrival = calendar.get(Calendar.HOUR_OF_DAY);
minute_of_arrival = calendar.get(Calendar.MINUTE);
}
}
/**
* This method changes the flight status to IN_QUEUE - simulates telling the
* plane to join queue
*/
public void directToJoinQueue() {
setFlightStatus(Status.IN_QUEUE);
}
/**
* This method changes the flight status to LANDING - simulates telling the
* plane to land
*/
public void directToflyToAirport() {
setFlightStatus(Status.LANDING);
time_when_called_to_land = time;
x_coord_when_called = x_coord;
y_coord_when_called = y_coord;
altitude_when_called = altitude;
}
/**
* This method reduces fuel level according to fuel usage
*/
private void useFuel() {
if (this.fuelLevelPercentage - TIME_STEP
/ time_taken_to_use_one_percent_of_fuel > 0) {
this.fuelLevelPercentage -= TIME_STEP
/ time_taken_to_use_one_percent_of_fuel;
} else {
this.fuelLevelPercentage = 0;
}
}
/**
* this method sets the flight status
*/
private void setFlightStatus(Status status) {
this.status = status;
}
public double getfuelLevelPercentage() {
return fuelLevelPercentage;
}
public int getPassengerCount() {
return passengerCount;
}
public void setPassengerCount(int passengerCount) {
this.passengerCount = passengerCount;
}
public int getAircraftNumber() {
return aircraftNumber;
}
public String getDepartureAirport() {
return departureAirport;
}
public void stop() {
;
}
public String getAirlineCompany() {
return airlineCompany;
}
public void setAirlineCompany(String airlineCompany) {
this.airlineCompany = airlineCompany;
}
#Override
public String toString() {
if (status == Status.LANDED) {
return String
.format("Flight %-8d | Fuel %-4.1f | Passengers %-3d | From %-10s | %-8s at %d:%d ",
aircraftNumber, fuelLevelPercentage,
passengerCount, departureAirport, status,
hour_of_arrival, minute_of_arrival);
} else {
return String
.format("Flight %-8d | Fuel %-4.1f | Passengers %-3d | From %-10s | %-8s | Coords (%-3.2f,%-3.2f) | Altitude %-4.2f",
aircraftNumber, fuelLevelPercentage,
passengerCount, departureAirport, status, x_coord,
y_coord, altitude);
}
}
public void start() {
aircraftThread = new Thread(this, this.getClass().getName());
aircraftThread.start();
}
#Override
public void run() {
try {
while (true) {
calendar = Calendar.getInstance();
fly();
Thread.sleep(TIME_STEP);
time += TIME_STEP;
}
// System.out.println("aircraft number "+aircraftNumber+" safely landed");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Cohesion is a difficult concept. Despite the other answer's flippant responses, the true answer depends very much on what your system does and how it works. For example lets examine the queue mechanism. In your system, does a plane respond to commands differently when in a queue? If so, then the fact that it is in a queue should be integral to the plane. Does it respond differently when in different queues? If so then the queue itself should be integral to the plane. If, however, it's the airport that responds differently because the plane is in a queue, then the airport should control the queue and the plane should know nothing about it -- it should simply be given a flight path by the airport (or by the control tower at the airport, depending on the resolution of your model).
Cohesion isn't your only problem here. Encapsulation is also a big issue. You are letting other objects have access to your internal state. To model this in a fully OO way, you should consider using the CQRS pattern. If you also consider DDD (Domain Driven Design) techniques, and start by identifying your bounded contexts and aggregate routes, you'll be more likely to derive a correct design.
There's no "standard" for Java or any other language.
I have a "plane" object which stores all the information I need to
sort the plane into a queue and pass to a database. All the vital
information is included in the object but I have also included the
co-ordinates for each plane.
I think your Plane model object is doing too much.
I don't see why it should know whether or not it's in a queue. I'd have a separate object that owns the queue know the rules.
Is queue an in-memory collection or a message queue? Does it matter to you?
Model objects persisting themselves is a point of debate. I think it's easier to separate persistence into a separate data access object so it's easier to test.
Your model might look like this:
package model;
public class Plane {
private int id;
public void save() {
// persist the state of this
// INSERT INTO PLANE(id) VALUES(?)
}
}
I'd have a DAO interface in a separate package:
package persistence;
public interface PlaneDAO {
void save(Plane p);
}
Cohesion can be defined as the degree to which the elements of a module belong together.
Visualizing it helps. Imagine the attributes of a class and the methods. If your class is cohesive, it means the methods are going to use many of the attributes, and conversely, the attributes will be used by many of the methods. This is the "sticking together" notion of cohesion. I like the following visualization that comes from NDepend's placemat:
As others pointed out, the methods that direct the plane (e.g., directToX) are possibly outside of the "theme" of what is a Plane, but they're not flagrantly wrong. Those elements (responsibilities) might be better in another class, say, AirTrafficController. In reality, planes don't decide much how they fly. Their pilots must follow instructions from the ground.
I'd argue that the Thread stuff (start, run) is definitely outside the theme of a Plane. Those methods hardly use anything that are part of a Plane (they are distractions from its theme). You could use an anonymous inner class to handle the processing in a thread from the main and your Plane would be even more reusable (and cohesive).
A cohesive object gets to the essence of the thing it models. This means it could more likely be re-used easily in another application (or even another OO language). Anything that starts to creep outside the true theme of your concept will likely make it harder to re-use the concept in another application. The "distractions" don't make sense anymore in another application.
If you're developing a Kamikaze project (one where you just want to make it work and don't care about re-use), it's perfectly OK to forget about cohesion (and other design elements). Design choices are trade-offs. You could refactor your Plane class to make it more cohesive, but if you never reuse it in another application, you've perhaps wasted your time. On the other hand, design is a learning process; even if you over-design something for one application, you maybe learned something for the next.
Finally, all design aspects are difficult to quantify and therefore there are few standards. Some companies have been known to set (arbitrary) standards for metrics such as LCOM in their development processes. I've read of team standards that say if a class has bad value for LCOM, then it must be refactored until its value goes low enough (its cohesion is stronger). Unfortunately, LCOM can be a bad measure of cohesion (especially in classes that have lots of get/set methods).
There is no java standard regarding object cohesion. (I don't repeat the advices of duffymo, I agree with all of them).
One thing to keep in mind when you elaborate an object model mapping the real world is to try to have one class mapping one concept of the real-world.
As an illustration, in your sample code you have at least 2 distincts concepts : Plane and Flight and so you can split them into 2 separate classes with a one-to-many relationship between them.

Categories