Hey I am new java so forgive me if what I am about to ask is obvious, but I will try to explain as best as I can.
Its just a project that has been set for university so its not in a serious manner.
I have a class called MarsRoom which holds the attributes say for all the dimensions of the room like the totalheight and width of the walls in order to calculate the heat loss that the room will suffer in order to adjust the amount of solar energy that is needed to keep the room at the room temperature set.
The problem I am having is what is better practice or solution, to pass the attributes of the size of the room in a constructor(but this could get quite long in size, as the ones below are not only the ones that I may need) or create a whole different class specifically for that room like ROOM TYPE U? and set the attributes in there.
As it stands I can create a whole new room just by instantiating the room with the new values, but its going to get a little long, whereas I would rather not create a whole new class for a different room which may only differ from another room by a few meters on one of the walls!.
So what I am really trying to get at it, is is it ok to pass that many attributes to the constructor on instantiation?
//the instantiation in the runnable
MarsRoom room1 = new MarsRoom("RoomU", 40, 40, 20, 20, 8, 2, 4);
//the constructor in the MarsRoom class
public MarsRoom(String roomname, int windowsH, int windowsW, int wallsH, int wallsW, int windowC, int heaters, int lights){
name = roomname;
TotalWindowHeight = windowsH;
TotalWindowWidth = windowsW;
TotalWallHeight = wallsH;
TotalWallWidth = wallsW;
windowCeiling = windowC;
numheaters = heaters;
numlights = lights;
roomheaters = new Heaters[numheaters];
}
I'd say that you should be adding factory methods here.
Basically, keep your constructor, but add methods like
static Room createLaundryRoom(laundryRoomParameters) {
return new Room(...laundry room parameters plus defaults
common to all laundry rooms...);
}
One of the great benefits object oriented programming is the possibility of not repeating yourself in code. Hence objects, which define data (members) and functionality (methods), and no requirement to create instances of these "prototypes" with hard values until run-time. To create a new class for each room when it
may only differ from another room by a few meters on one of the walls
would be to deny OOP (and Java) by gross repetition. I'd stick with the constructors, and if similar kinds of rooms end up emerging, try one of the static factory methods suggested, or break up common functionality using inheritanceOracle.
Create a map with the keys being
Map<String, Integer> map = new HashMap();
map.put("TotalWindowHeight", new Integer(10));
map.put("TotalWindowWidth", new Integer(5));
...
map.put("NumberOfHeaters", new Integer(3));
MarsRoom room1 = new MarsRoom("RoomU", map);
Constructor will be like:
public MarsRoom(String roomname, HashMap<String, Integer> params) {
name = roomname;
TotalWindowHeight = map.get("TotalWindowHeight").intValue();
TotalWindowWidth = map.get("TotalWindowWidth").intValue;
...
roomheaters = new Heaters[map.get("NumberOfHeaters").intValue()];
}
this is not good OO however, but it seems like you are looking for something quick. If you want good OO you need to create an object for Window and in it you have hieght and width, another for ceiling, and you should not have number of something as a field, you should have an array to store the heater objects, and so and so forth, but this is quick and meets your requirement.
While technically legal, constructors with very long argument lists may be inconvenient to use. It also depends on whether you this the list may grow in the future or in subclasses.
If you have many parameters, but they have defaults and sometimes only a few need to be changed, you may find the Builder pattern useful. The idea is to replace constructor arguments with function calls, and allow them to be chained, for example:
public MarsRoom() {
//empty or just basic stuff set here
}
public MarsRoom setTotalWindowHeight(int TotalWindowHeight) {
this.TotalWindowHeight = TotalWindowHeight;
return this;
}
public MarsRoom setTotalWindowWidth(int TotalWindowWidth) {
this.TotalWindowWidth = TotalWindowWidth;
return this;
}
...
then, you can call:
MarsRoom room1 = new MarsRoom()
.setTotalWindowHeight(20)
.setTotalWindowWidth(40);
Of course, if you wanted to set all parameters this way, it's longer (thou maybe more readable) than the single constructor. But if you only set 2 parameters out of 10, it will usually be more convenient.
You don't show what the fields of MarsRoom are, but for each feature, I would have a Collection of sub-objects. A MarsRoom has-a List of Windows. A MarsRoom has-a List of Walls. etc... Then have setters and getters for each and methods to add new instances of these features.
Since this is for school, I'm only including a little bit of pseudo code.
public class MarsWindow {
int height;
int length;
// Setters & Getters
// standard getters & setters go here
int getArea() {
return this.height * this.width;
}
}
public class MarsRoom {
List<MarsWindow> windows;
List<MarsWall> walls;
List<MarsLight> lights;
List<MarsHeater> heaters;
public List<MarsWindow> addWindow(MarsWindow window) {
// Add a window to the "windows" list here
}
public List<MarsWall> addWall(MarsWall wall) {
// Add a wall to the "walls" list here
}
// Do this for the other fields
int getTotalWindowArea() {
int area = 0;
// Iterate over all windows
for(MarsWindow window : windows) {
area += window.getArea();
}
return area;
}
// Add other calculation methods here
}
If what you're trying to do is simply not duplicate the parameters you're passing the constructor, you can simply put them in a separate static method, like so:
public static MarsRoom newRoomU() {
return new MarsRoom("RoomU", 40, 40, 20, 20, 8, 2, 4);
}
You could also use some polymorphism or have different types of rooms or something similar to this and then have a superclass with the common values that all rooms will have.
You can also have more than one constructor and have different ones for values you wish to set depending on the room type etc.
Its always better to work with objects rather than primitives, you could use factory to create objects.
//the constructor in the MarsRoom class
public MarsRoom(String roomname, WindowDimension windowDimension, WallsDimensions wallDimension, RoomAmbience ambience){
}
public class WindowDimension{
private int height; //int windowsH
private int width; //int windowsW
private int circumference; //assumed windowC is circumference
}
public class WallsDimension{
private int height; //int wallsH
private int width; //int wallsW
}
public class RoomAmbience{
private int heaters;
private int lights;
}
Related
I don't have idea how to add to array enum. I made constructor using fields with enum and its works, but I don't know how to make it in constructor without field. I hope that you understand what Im thinking about. In my code I comment where I think i have problem.
I've got:
public enum Components {
WIFI, BLUETOOTH, CAMERA, SSD
}
public Laptop(){
System.out.println("name of producer:");
String producername = Main.sc.nextLine();
System.out.println("name of model:");
String modelname = Main.sc.nextLine();
System.out.println("ram:");
int ram = Main.sc.nextInt();
System.out.println("cpu:");
String cpu = Main.sc.nextLine();
cpu = Main.sc.nextLine();
System.out.println("components:");
System.out.println("how many components do you want to add?");
int z = Main.sc.nextInt();
Components[] com = new Components[z];
for(int i=0; i<com.length;i++){
com[i] = //<-- how to add enum in array?
}
setProducerName(producername);
setModelName(modelname);
setRam(ram);
setCpu(cpu);
setComponents(com);
}
My constructor using field is like that and it works.
public Laptop(String ProducerName, String ModelName, int Ram, String Cpu, Components... components) {
super();
this.ProducerName= ProducerName;
this.ModelName= ModelName;
this.Ram= Ram;
this.Cpu= Cpu;
this.components= new Components[components.length];
this.components= Arrays.copyOf(components, components.length);
}
Please help.
You could get the enum value by its name.
public enum Components {
WIFI, BLUETOOTH, CAMERA, SSD
}
public Laptop(){
...
Components[] com = new Components[z];
for(int i=0; i<com.length;i++){
com[i] = Components.valueOf(Main.sc.nextLine());
}
...
}
I'm not 100% clear what you're asking, but you can get an array filled with your enum constants from the enum itself: Components.values() will return an array of all the enum constants. It will essentially return:
new Components[]{Components.WIFI, Components.BLUETOOTH,
Components.CAMERA, Components.SSD}
Side recommendation: don't use Scanner inside of your Laptop constructor, and in fact, get all user interface code out of all constructors and instance methods of that class. All user interface code belongs elsewhere.
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()];
}
}
The purpose of the program is to calculate the volumes of different geometrical figures (Like a cylinder or a pyramid). I've started out by adding a list where the user can choose between the different figures.
The problem is that I don't know how to make the program know which formula to use. I need to be able to separate the choices instead of just making an int out of the answer.
private void btnAktiveraActionPerformed(java.awt.event.ActionEvent evt) {
String form = listForm.getSelectedValue().toString();
int fo = Integer.valueOf( form );
String höjd = txfHöjd.getText().toString();
int hö = Integer.valueOf( höjd );
String bredd = txfBredd.getText().toString();
int br = Integer.valueOf( bredd );
String radie = txfRadie.getText();
int ra = Integer.valueOf(radie);
String djup = txfDjup.getText();
int dj = Integer.valueOf(djup);
double ACyl = 3.14*ra*ra*hö;
double APyr = (br*dj*hö)/2;
double AKub = br*dj*hö;
double ARät = br*dj*hö;
txfHöjd.setEnabled(false);
txfBredd.setEnabled(false);
txfDjup.setEnabled(false);
txfRadie.setEnabled(false);
listForm.setEnabled(false);
}
private void btnBeräknaActionPerformed(java.awt.event.ActionEvent evt) {
// I know this code won't work, its just a reminder.
if (answer == Cyinder){
System.out.print("volymen är: "+ACyl+" cm^3");
}
}
I don't understand your question very clearly. I would suggest to make a plan to solve your problems.
make a list of figures that program will calculate
make a list of methods to count volumes of those figures
create individual classes, variables etc...
create methods
create main method with user input
You mentioned you don't know which formula to use. I assume there won't be many formulas in your program. I would create an individual method for each individual figure i.e. piramidFormula(), cilinderFormula()...
There is no point to refer to polimorphism when I think your level of programming is very basic at this stage.
I hope that will help you a little bit.
You need a list to hold the things, you seem to understand this just fine.
You need a way to select things. Selection is typically not exactly the same thing as the list, you need a class to be responsible for the "selection" behaviour.
Each thing has a routine that can calculate the volume. That means it will need input parameters. This is where it starts to get tricky, because if you want all of your things to be in the same list, you need to decide how to manage the different input parameters for the different types in the list.
public List<VolumeCalculations> volumeCalculations ...
public interface VolumeCalculation {
public double getVolume();
}
public class CubleCalcuation implements VolumeCalculation {
private double side = 0;
public void setSide(double value) {
this.side = value;
}
#Override
public double getVolume() {
return side*side*side;
}
}
the other volume calculations are left as an exercise to you.
Then you need to put them all in the list
volumeCalculations.add(new CubeVolumeCalculation());
...
But when you select the calculation, you will need "something" to ask for the right input.
public interface CalculationInputGather {
public void setCalcualtion(VolumeCalcuation value);
public void askForInputs();
}
which the one for the CubleCalcuation might look like
public CubeInputGather implements CalculationInputGatherer {
#Override
public void setCalculation(VolumeCalcualtion value) {
if (value instanceof CubeCalcuation) {
this.volume = value;
}
throw new IllegalArgumentException("value must be a CubeCalculation");
}
public void askForInputs() {
System.out.println("enter the side value:");
// read the value
volume.setSide(value);
}
}
then when you know the selected item in the list, you can use a Map of Calcuations to their input gatherers to lookup the right input gatherer for the selected calcuation.
If you already have the list for the user to choose from, maybe consider a map instead. You can have all your shapes as the keys of the map and then the formulas for volume as the values of the map. The list of shapes can be provided to the user via the keySet and their response can be matched back against the map to find the formula.
EDIT: You have your formulas for each shape inside an action event. You'll need to move those into a separate class
public static class Formulas() {
// list all formulas here
private String cylinder = "3.14*r*r*h";
}
Then when you hit the action you can either create a new instance of the Formulas class and use any convenience methods you might write in there.
How do I combine two methods that have identical calculations but operate (read and write) different fields of the class.
A VERY simplified aircode example:
class TileCalculator
{
int length;
int width;
int tileLength;
int tileWidth
int cols;
int rows;
void calculateColumns()
{
this.cols = this.width/this.tileWidth;
}
void calculateRows()
{
this.rows = this.length/this.tileLength;
}
}
As these two methods do exactly the same calculation(s) but just using different fields for their input and output it would seem sensible to combine them but I don't know how.
UPDATE: I think I may have oversimplified it to the point where answerers are trying to solve the specific case. A more realistic example is:
void calculateCols()
{
int tileCols = width/tileWidth;
int remainder = width%tileWidth;
if (remainder==0) {
// there is an exact number of whole tiles
fullTileCols = tileCols;
firstT = tileWidth;
usedTileCols = tileCols;
} else {
// there is a remainder
fullTileCols = tileCols - 1;
firstT = (remainder+tileWidth)/2;
usedTileCols = tileCols + 1;
}
}
void calculateRows()
{
int tileRows = length/tileLength;
int remainder = length%tileLength;
if (remainder==0) {
// there is an exact number of whole tiles
fullTileRows = tileRows;
firstCut = tileLength;
usedTileRows = tileRows;
} else {
// there is a remainder
fullTileRows = tileRows - 1;
firstCut = (remainder+tileLength)/2;
usedTileRows = tileRows + 1;
}
}
I'm not saying a redesign isn't the answer but as you can see there are multiple fields involved so a simple return value probably isn't going to cut it. This is why I am using fields rather than a simple function and the maintainability of the current setup is of concern to me.
No, I wouldn't combine them, I would change them.
I'd get rid of rows and cols fields
I'd get rid of the above methods as it makes your object's state dependent on these methods always being called before an object is used -- a risky proposition.
Instead I'd create two calculated getter methods. This way the calculations are guaranteed to be done when needed.
e.g.,
public int getColumns() {
return width / tileWidth;
}
public int getRows() {
return length / tileLength;
}
Edit
I suppose you could create a RowCol class that has full, first, and used fields, and that has but one equation for doing the calculation above, and that you create two instances, one for row and one for column in the containing class, but if the rationale for this is to just combine these small methods, I question the need for this, or the benefit. Yes, you should follow the DNRY rule, but I worry more about this when I have three or more repeats of the same code.
You could make a convenience method. In the case you have shown this is actually more typing, longer program, extra complexity etc for no benefit. But if the calculation was more complicated it could be worth it
int calculate(int a, int b)
{
return a/b;
}
void calculateColumns()
{
this.cols = this.calculate(this.width, this.tileWidth);
}
after the update
you actually want 3 return values(full, first, used) so alter the "calculate" to either return a special class with 3 int or an array of int
Then feed in a and b as before but with the adjusted logic and return the 3 values and set them in the calling function
There is no easy way to do this in Java prior to Java 8. You can do it, but it involves using private internal interfaces and anonymous classes. It isn't worth it unless you're really talking about a lot of common lines of code.
With Java 8 though, you'll be able to use closures which will greatly simplify this kind of cases.
I am creating a text based game and I am having some issues.. This is what I have so far. So far I have a Combat Class, and two Classes for two different Weapons. I am trying to assign hit points to the weapons themselves. But my biggest issue is in the Combat class. I am trying to create it to were there will be random weapon drops at random times and also random Weapons. So far in the Combat class I have this:
public class Combat {
final int chanceOfDrop = 3;
static Weapons[] wepArray = {new M4(), new M16()}
static boolean[] hasWeapon = {false, true};
public static int ranNumberGen(int chanceOfDrop) {
return (int) (Math.random()*1);
}
private void enemyDead() {
boolean canDrop = false;
if(ranNumberGen(chanceOfDrop)==0){
canDrop = true;
}
if(canDrop == true){
givePlayerWeapon(Weapon[Combat.ranNumberGen(Weapons.length)]);
}
private static void givePlayerWeapon(int w) {
hasWeapon[w] = true;
for w <(Weapons.length-1) {
if has weapon[w] {
System.out.println(wepArray[w].getWeaponName);
}
}
}
}
}
}
I have issues when I am creating the new M4(), and the new M16() it says Type mismatch: cannot convert form M4 to Weapons. I do have a class named Weapons, could that be the problem?
And here is my M4 Class, both M4 and M16 Classes are identical
public abstract class M4 {
private Integer weaponDamage = 5;
private Integer weaponAmmo = 25;
private String weaponName = "M4";
public M4(String name, int ammo, int damage) {
name = weaponName;
ammo = weaponAmmo;
damage = weaponDamage;
}
public String getWeaponName() {
return weaponName;
}
public Integer getAmmo() {
return weaponAmmo;
}
public Integer getDamage() {
return weaponDamage;
}
}
I don't think I have any issues here. Maybe my problem lies within this though. Although, I have a Weapons class, but nothing in it. Do I need that?
A few things to fix at first sight:
Create a generic Weapon class that defines some properties that apply to each weapon, like name, damage, ammo, scope multiplier, etc... Then create subclasses for Weapon, like M4 and M16, that specify the properties and eventually add weapon-specific properties.
Add brackets to this line:
System.out.println(wepArray[w].getWeaponName); // Change to getWeaponName()
Remove the abstract keyword from M4.
Fix the ranNumberGen method because it will always return 0 right now. Math.random() returns a float in the range [0,1[. This means that casting it to an int will always result in 0. Multiply it by n to have a random int in the range of [0, n[. You probably want this:
public static int ranNumberGen(int max) {
return (int) (Math.random() * max);
}
Change this line:
givePlayerWeapon(Weapon[Combat.ranNumberGen(Weapons.length)]);
to:
givePlayerWeapon(wepArray[Combat.ranNumberGen(wepArray.length)]);
The syntax of a for-loop is like this:
for (variable-initialization; condition; increment)
So in your case, you want:
for (int i = 0; i < hasWeapon.length; ++i)
{
if (hasWeapon[i]) System.out.println(wepArray[i].getWeaponName());
}
You might want to revisit your decision to use an inheritance-style heirarchy for game objects before it is too late.
In practice, I've found a component-entity model and/or prototype model to be much more effective. You could take a look at the code in my old Java roguelike game Tyrant for inspiration:
Weapon definitions: mikera/tyrant/Weapon.java (Github is down right now so can't find the exact link, but should be easy enough to Google)
The idea is that you make your objects by setting properties / composing compoenents in a Map-like game object rather than using static inheritance.
When you want to create a random weapon in this model, you can just get a list of all the possible weapon prototypes, and clone one of them at random to make a new weapon.
the mean of abstract in "public abstract class M4" is that you cannot make a new object with this class.
So you can put all commons fields of your weapons in the weapon class and make m4 and m16 extends the weapon and you code would compile.