I apologize if my question lacks clarity,
I'm currently working on a school assignement where I have to use the following Enum class:
public enum Seeds {
TOMATE,
CONCOMBRE,
SALADE,
PATATE,
BETTERAVE;
}
Rather then making a whole bunch of constants for the buy price, sell price and maturation time of each seed and having to type them out each time, I wanted to assign attributes to each enum directly in the class like so:
public enum Seeds {
TOMATE(2.00, 3.50, 5),
CONCOMBRE(1.00, 2.50, 6),
SALADE(1.50, 4.50, 8),
PATATE(2.50, 3.50, 4),
BETTERAVE(2.00, 4.00, 10);
private final double
buy_price,
sell_price;
private final int
maturation_time;
public Seeds(double buy_price, sell_price, int maturation_time) {
this.buy_price = buy_price;
this.sell_price = sell_price;
this.maturation_time = maturation_time;
}...
and return their attributes with getters.
However, my teacher told me that I cannot modify the provided Enum class... so I was wondering if it was possible to construct the seeds in another class.
If you can't modify the Seeds enum, you could create a POJO to hold all the info you need like this:
public class Seed {
private Seeds seedType;
private double buyPrice;
private double sellPrice;
private int maturationTime;
// constructor, getters and setters here
}
It would be better to add the properties and a constructor to the Seeds enum though.
You can create a custom class that encapsulates the different price types, and keep a Map<Seed, YourCustomPricesClass> to store the relations.
See: the Map interface in the Java Tutorial
Yes it is possible, but you are eroding the main intent behind creating an enum. If you are going to create a modifiable state of a class, technically you are creating a new object. If that is the case, You don't even need an enum at first place, just stick with class.
Related
I'm new to coding and I've faced this problem recently: I'm working on a class which has various fields, and I want to insure each instance of the class has a unique value for a certain field using static variables. for example, consider this class:
public class NetworkNode {
private String NodeName;
private int NodeNumber;
private boolean NodeAttraction;
....
}
in the code above, I want to insure each object created from the class NetworkNode to have a unique and different NodeNumber or in other words, no two NetworkNode objects should have the same NodeNumber field.
what are the ways to do this? thanks.
You could automatically assign a different NodeNumber to each instance if you don't care about the actual value as long as it's unique. Using static variables you could create a private static counter nextNodeNumber in your class NetworkNode:
private static int nextNodeNumber = 0;
In your constructor you could then do
public NetworkNode() {
this.NodeNumber = nextNodeNumber;
++nextNodeNumber;
...
}
This way you just have to ensure, that there is no other way to set/change NodeNumber or nextNodeNumber.
If you are using multiple Threads you would have to secure access to nextNodeNumber to prevent asynchronous access.
1 put a
static Set<String> myuniquevalues ... (for example) for each of your fields
2 in your constructor
public NetworkNode (String value1 ...)
{... check if value1 exists in myuniquevalues , and throw exceptions }
3 if your objects are deleted, you must manage it also ...
Alternative: concentrate creation of your objects in a factory, and manage unicity there.
I recommend you to do some reading about variables and what static means. To make it short, a static variable exists only "once" in your program.
For example, if you create a game, you want the variable score to be static since there will only be one instance of this variable.
In order to have each NetworkNode to have a unique and different NodeNumber, you have to construct the object like this:
public NetworkNode(String NodeName, int NodeNumber, boolean NodeAttraction){
this.NodeName = NodeName;
this.NodeNumber = NodeNumber;
this.NodeAttraction = NodeAttraction;
}
See, here, each NetworkNode will have a different value for each of the variables passed as parameters.
You will then just need to create the object in your main function or whatever like this for example:
NetworkNode myNode = new NetworkNode("node1", 0, true);
Hope it helps,
I have a large collection of classes. These classes have similar properity names but with different values. For example, I have Spearmen, and Swordsman. These two classes have the same properity names but with different values for them. Now. Suppose I have another class. Entity. How can I call the class's constructor and specifiy which type of unit the entity should be, Without going through a chain of if statements to decicide whether the object is more specifically a type Swordsman or a type Spearmen or an ... Through all my classes.
I can make a simple runnable example but i'm not sure if it is necessary as I have explained myself above
What i can recommend you to do is to create an base class, lets call it hero
public class Hero
{
public HeroType Type { get; set; }
public int Power { get; set;}
public Hero(HeroType type, int power){
this.Type = type;
this.Power = power;
}
....
}
and then create an enum of hero types:
enum HeroType{
Spearmen,
Swordsman,
...
}
Every time you create a new hero you just need to specify his type like so
Hero swordsman = new Hero(HeroType.Swordsman,50)
this way you son't need to create multiple classes and you can save all your objects in the same collection because they all from the same base type.
And if you need a special Hero that has more properties you can create a new class that inherit from the Hero base class.
If you want to find out the class name of an object you could try:
String className = variable.getClass().getSimpleName();
java reflection API will give you methods to accomplish what you need. Object.getClass()....
So I've learned a bunch recently so I'm going back and sort of refactoring the homeworks from a previous course that I took to implement them using good practices. One homework had us implement a Planner object that contained an array of Course objects. I'm trying to create some Course constants so that I can access some popular Courses without having to create brand new Objects every time and so I can easily access them without going through the Course building process. I don't have much experience with enums and I can't seem to find anything on how I can actually use an Enum to store constants that are Objects. I originally wanted to make them constants in the Course class but Effective Java insists enumns should be used in such a situation. Does my implementation make sense at all? How should I go about making this enum that contains Course constants so I can actually retrieve them? I use the Builder method for creating a Course.
public enum Courses {
CSE_114, CSE_214, CSE_219, CSE_215;
private final static Course CSE_114_COURSE = new Course
.Builder("Computer Science 1", "Paul Fodor", 114)
.section((byte)1).department("CSE").build();
private static final Course CSE_214_COURSE = new Course
.Builder("Data Structures", "Ahmad Esmaili", 214)
.section((byte)1).department("CSE").build();
private static final Course CSE_219_COURSE = new Course
.Builder("Software Development", "Richard McKenna", 219)
.section((byte)1).department("CSE").build();
private static final Course CSE_215_COURSE = new Course
.Builder("Foundations of CS", "Paul Fodor", 215)
.section((byte)1).department("CSE").build();
public static Course get(Courses c) {
switch(c) {
case CSE_114: return CSE_114_COURSE;
case CSE_214: return CSE_214_COURSE;
case CSE_219: return CSE_219_COURSE;
case CSE_215: return CSE_215_COURSE;
default: throw new IllegalArgumentException("Course does not exist.");
}
}
}
You can actually treat an enum like an object:
public enum Course {
CSE_114("Computer Science 1", "Paul Fodor");
public final String room;
public final String lecturer;
private Course(room, lecturer) {
this.room = room;
this.lecturer = lecturer;
}
}
Because it is an enum, all values must be known at compile time. This is enforced by the Java language, which requires that the enum constructor is private.
While this would work for your situation, I don't recommend it - in fact, I don't recommend using an enum at all. An enum represents a fixed, known set of values. If you want to create more courses at runtime, then the enum is incomplete, and that contradicts the definition of an enum.
Instead, I suggest you use a CourseManager. Create one class, which holds the collection of all known courses. Then, when you need a course, you request it by name.
Course cs114 = courses.get("CS 114");
You could also take it one step further, by instantiating the CourseManager from a file, which contains a list of courses in a basic format like JSON.
That's not a bad implementation but I think a have a bit better solution: add an abstract method to your enum definition.
public enum Courses {
CSE_114 {
public Course getCourse() {
return CSE_114_COURSE;
}
}
...
private final static Course CSE_114_COURSE = new Course
.Builder("Computer Science 1", "Paul Fodor", 114)
.section((byte)1).department("CSE").build();
...
public abstract Course getCourse();
}
That way you can access to any course object vía Courses.CSE_114.getCourse() and you are also forcing that every enum has a course (imagine that you add an enum constant but forgot to add it in the get method. The way I proposed makes that scenario non sense)
You are mixing enum constants with static constants. Get these courses and selection of courses out of the enum class. Or you can use something like Andrew Williamson showed. Just don't mix the static constants with the enums. Static constants don't belong to the enum class. Enum class has a fixed set of values and that is where its role ends. All the other logic using these enums should be done somewhere else
Consider the following
public enum tc implements {
NORESULTS(0), GOOD_RESULTS(1), EXCELLENT_RESULTS(2), NO_DATA_AVAILABLE(5), SOME_OTHER_VALUE(4);
private final Integer value;
// Code for the constructor, getters and setters for the value****
The enum tc values correspond to the testValue in the below class.
public class TestData {
private int testID;
private String testName;
private int testValue;
....
...
}
In the Results class, the TestDataList has to be sorted by a different order of ranking rather than testValue.For example Excellent followed by Good Results followed by NoResults etc..
public class Results {
List<TestData> TestDataList = getTestData();
I can code for the comparator etc..the question is since I require a different ordering for the enums which of the following two options is better
a) add private int rankTestValue in the enum tc. This option may require that I have to write a method getRank(int value) that would return the corresponding rankTestValue based on the value.
OR
b) add in Results class a map Map tcRankMap = new HashMap();. Populate this map with key values like (2,1) (1,2) corresponding to (enum values, ranking).For example (2,1) would be Excellent_Results has first ranking etc.
Which of these two options would be better. If there are better solutions then please let me know.
Option (a) looks better and according to Object Oriented Analysis and Design.
The good news is that the is a question of implementation detail which can be encapsulated into your Comparator anyway, so it doesn't matter so much.
As for style and readability, I would prefer (a), but it's down to personal preference.
There is also a solution (c) - use the ordinal(), and then sort them according to rank. Just add a comment to make it clear
public enum tc implements {
// NB: enum values are sorted according to rank
EXCELLENT_RESULTS(2),
GOOD_RESULTS(1),
NORESULTS(0),
NO_DATA_AVAILABLE(5),
SOME_OTHER_VALUE(4);
private final Integer value;
// Code for the constructor, getters and setters for the value****
}
Your first option would look like this:
enum TestScore {
EXCELLENT(5),
NO_RESULT(2),
POOR(1);
private final int order;
private TestScore(int order) {
this.order = order;
}
public int compareOrderTo(TestScore other) {
return this.order - other.order;
}
}
You could then add a comparison method to TestData
public int compareTestScore(TestData other) {
return this.testScore.compareOrderTo(other.testScore);
}
And sort your list with:
Collections.sort(testData, TestData::compareTestScore);
The problem with this is that the order field is really completely arbitrary and needs to be updated each time you add a new entry. However that's definitely better and more explicit than using the natural ordering of the enum (i.e. it's ordinal value which should be entirely incidental to avoid fragility).
I am writing a program to simulate cities from a game called Civilization 4. In order to do this I have several Enums to represent types of terrain, resources, improvements etc for each plot owned by said city.
The problem is I want to program to be compatible with Fan made mods which may add things to the Game that need to be accepted into my independant utility. So I thought of creating a Enum style class to hold the new types defined by the loaded mods (as Enums cannot be changed at runtime) which is created during runtime when the user enters in a mod to be loaded (which is a txt file that is parsed to read the new additions)
So is there a way to simulate Enums that are created and added to at runtime? I take it static member variables cannot be used as they are done before runtime...
You can make a enum implement an interface.
This way you can have your defined values in the enum, but new values can be any class which implements the interface.
An alternative is that you generate or load the enum at runtime using a byte code generator or the Compiler API. I wrote a library to make it easier to take a String and compile&load it.
http://vanillajava.blogspot.co.uk/2010_11_01_archive.html
Well, enums in Java are simply classes where the language guarantees that the set of known objects is known and limited at compile-time. If you want to add new enum literals at runtime, you end up with regular classes.
The beauty of enums is that you can write human readable names in code that are compiled as numbers behind the scenes, because computers like numbers better. Take for example this enum:
enum Season { WINTER, SPRING, SUMMER, AUTUMN }
Behind the scenes WINTER might be 0 (zero), SPRING is 1 etc.
To replicate this behaviour in runtime code you could create a list of strings, like this:
List<String> seasons;
seasons = new ArrayList<String>();
seasons.add("Winter");
seasons.add("Spring");
...
That way you can reference the items as numbers, such as seasons[1] would equal "Spring".
This answer is just one of many ways to approach this question.
By default, enum types have only a set number of values. The values in an enum type are actually declared as static final, and there's no way to add more on runtime.
That being said, there are other patterns you can use to implement what you want. Let's take a look at using an interface and a registration system. We'll start with the Terrain interface:
public interface Terrain {
int getId();
String getName();
int getSightBonus();
}
Now an enum, DefaultTerrain:
public enum DefaultTerrain implements Terrain {
PLAINS(0, "Plains", 1),
HILLS(1, "Hills", -1),
MOUNTAINS(2, "Mountains", -2);
private int id;
private String name;
private int sightBonus;
private DefaultTerrain(int id, String name, int sightBonus) {
this.id = id;
this.name = name;
this.sightBonus = sightBonus;
}
public int getId() {return id;}
public String getName() {return name;}
public int getSightBonus() {return sightBonus;}
}
And a registration class, which can be either a static utility class or a singleton.
public class TerrainManager {
private static Map<Integer, Terrain> terrainsById = new HashMap<>();
static {
for (DefaultTerrain terrain : DefaultTerrain.values())
register(terrain);
}
public static void register(Terrain terrain) {
Integer id = terrain.getId();
if (terrainsById.contains(terrain.getId()))
throw new IllegalArgumentException("Terrain with id already exists: " + id);
terrainsById.put(id, terrain);
}
public static Terrain getTerrainById(int id) {
return terrainsById.get(id);
}
public static Set<Terrain> getAllTerrains() {
return new HashSet<Terrain>(terrainsById.values());
}
}
This last class is where the magic happens. Presumably the modders will have some kind of identifier in the game's world definition to say "use this tile," right? In this case, I've called it an integer, id, but really it could be any type, just modify the Map accordingly. In the map-loading code, just use the ID in the world definition to look up the Terrain. When a modder adds a new Terrain, they just need to implement Terrain and register it with TerrainManager.
The static initializer makes sure that your DefaultTerrain objects are added before anything else is added. If you use a singleton, this could be put into the class constructor instead.
Use this pattern for your different enum types that you want users to add to. You could also use it for pretty much any other type as well besides enum.
You will need CGLIB, http://cglib.sourceforge.net/