Storing and calling specific class methods in/from an array - java

I've been reading and googling for hours on how I can call
public class Fee {
int id;
String name;
double amount;
FeeCategory feeCategory; // miscellaneous, other, tuition, etc
GradeLevel gradeLevel;
SchoolYear schoolYear;
String description;
boolean isActive;
public boolean isIsActive() {
return isActive;
}
public void setIsActive(boolean isActive) {
this.isActive = isActive;
}
public FeeCategory getFeeCategory() {
return feeCategory;
}
public void setFeeCategory(FeeCategory feeCategory) {
this.feeCategory = feeCategory;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getAmount() {
return amount;
}
public void setAmount(double amount) {
this.amount = amount;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public GradeLevel getGradeLevel() {
return gradeLevel;
}
public void setGradeLevel(GradeLevel gradeLevel) {
this.gradeLevel = gradeLevel;
}
public SchoolYear getSchoolYear() {
return schoolYear;
}
public void setSchoolYear(SchoolYear schoolYear) {
this.schoolYear = schoolYear;
}
I have a number of different getter methods along with its setter methods.
I need to be able to call the method to fill the cells of a JTable with specific values returned by corresponding getter method.
So what I did was create a DefaultTableCellRenderer
public class JTableRenderer extends DefaultTableCellRenderer{
#Override
public Component getTableCellRendererComponent(
JTable table, Object value,
boolean isSelected, boolean hasFocus,
int row, int col)
{
Component cellComponent = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
if(row%2 == 0){
cellComponent.setBackground(Color.YELLOW);
}
else{
cellComponent.setBackground(Color.CYAN);
}
for(int i=0; i<table.getRowCount(); i++){
for(int j=0; j<table.getColumnCount(); j++){
if(table.getValueAt(i, j) instanceof Fee){
Fee fee = (Fee)table.getValueAt(i, j);
table.setValue(fee.getId(),i,j);
}
}
}
return cellComponent;
}
}
The problem is with the for loop which I plan to use to set specific values for certain cells.
As you can see, it filled all the cells with just the id because I can't think of a way to iterate through getId(),getName(),getAmount(),getDescription().
Is it possible to put all 4 methods in an array maybe something like
Methods[] myMethods = {getId(),getName(),getAmount(),getDescription()};
then,
for(int i=0; i<table.getRowCount(); i++){
for(int j=0; j<table.getColumnCount(); j++){
if(table.getValueAt(i, j) instanceof Fee){
Fee fee = (Fee)table.getValueAt(i, j);
table.setValue(fee.myMethod[j],i,j);
}
}
}
I want to call just the 4 getter methods but not all of them.
Any solution or suggestion?

You are going to need some sort of switching logic to handle the mapping of index to getter method. For me, the neatest way is to use Java 8 lambda functions, something like the example below. As you can see, this adds a getValue(int index) method to the Fee class which does what you want. The mapping is handled by a Map created in the static initialisation.
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
public class Fee {
private String name;
private int fee;
private static Map<Integer, Function<Fee, Object>> getterIndex = new HashMap<>();
static {
getterIndex.put(0, Fee::getName);
getterIndex.put(1, Fee::getFee);
}
public String getName() {
return name;
}
public Fee setName(String name) {
this.name = name;
return this;
}
public int getFee() {
return fee;
}
public Fee setFee(int fee) {
this.fee = fee;
return this;
}
public Object getValue(int index) {
return getterIndex.get(index).apply(this);
}
public static void main(String[] args) {
Fee fee = new Fee().setName("Barry").setFee(1000);
System.out.println("name: " + fee.getValue(0));
System.out.println("fee : " + fee.getValue(1));
}
}

In order to dynamically call methods like that, you'll need to use reflection and possibly introspection.
Reflection is when you programmatically use the structures of your program itself, such as Class instances, the methods they define. If you take a look at the Java Class class, you'll find it has methods for accessing its constructors, fields, methods and more.
Introspection is the ability to use properties of some object at run-time. Classes that conform to the JavaBeans specification allow introspection, which offers some abstraction that's easier to use than pure reflection. The Introspector class in package java.beans allows you to obtain bean info for a class. From there, the "properties" of that class can be used. A property could be a field with a getter and/or setter, or a getter/setter not backed by a field (that may simply operate on logic). It allows for more than that, such as registering a listener with a property on an instance so that if the property is changed through a setter, the listener is called. This is useful for a model-view-controller approach, where changes to some instance may require update events being fired on the view. For example, if some part of your code changes properties of objects that are represented as rows in your table, outside of the GUI, the listener could be used to update the corresponding cell.
If you want to use an array, you'll have to populate it with Method instances. These would be the read methods (and possibly a separate array with write methods) for the corresponding PropertyDescriptors you get via the introspection. Such a Method can then be invoked on an object, provided the access rules allow it. It might actually be better to use a Map, which maps names to the Method, so the actual order doesn't matter. This would make it easier to refactor your user interface later. You may also want some way of mapping the actual column names to the property names, but if you set specific rules regarding naming and stick to them, you could derive the property names from the column names, or reverse things and show a column for each property automatically.
EDIT: Maybe interesting to know why you need to do these things in such a round-about way. Java does not have first class methods. This means that methods cannot be passed around as arguments or treated as any other piece of data, the way you could in JavaScript or Scala. So reflection is needed to obtain and invoke methods indirectly. Java 8 introduced some functional programming concepts with lambdas, but they are a form of single-method interface in disguise. Furthermore, Java is not a dynamic language such as Ruby or Python, it is a statically compiled language. So some things that are simple (but also easy to break) in other languages require reflection in Java. If you come from a non-Java background, the way you need to do some things may feel cumbersome.

Add to Fee class:
public Object myMethod(int j) {
switch (j) {
case 0:
return this.getId();
case 1:
return this.getName();
case 2:
return this.getAmount();
case 3:
return this.getDescription();
default:
throw new IllegalArgumentException();
}
}
You should have a list of Fee records:
List<Fee> feeData=new ArrayList<Fee>();
Then call:
for(int i=0; i<feeData.size(); i++){
if(feeData.get(i) instanceof Fee){
for(int j=0; j<table.getColumnCount(); j++){
Fee fee = (Fee)feeData.get(i);
table.setValueAt(fee.myMethod(j),i,j);
}
}
}

Related

Check if class has a variable in its constructor based on a string?

Let's say I have a class named Person and its constructor had variables like name, age, hairColor and so on. If I had a function that receives a string that should match one of the class's variables, how could I check if that class actually had that variable and how could I go about modifying it? For example:
public class Person {
public String name;
public int age;
public String hairColor;
public Person() {
name = "Bryce";
age = 21;
hairColor = "brown";
}
public void changeHairColor(String variable, String color) {
if (/*this class contains the variable passed as an argument to this method*/) {
// Person[variable] = color
}
}
}
I'm a python dev, mostly, so the method changeHairColor has some pseudo-python in it. I want to be able to edit the variable in a similar way you could edit variables inside of dictionaries with Python:
person = {
"name": "Bryce",
"age": 21,
"hairColor": "brown"
}
def changeHairColor(variable, color):
person[variable] = color
If that is at all possible.
The only way to do it in Java is to use Java Reflection API:
public class Test {
public String name;
public int age;
public String hairColor;
public void setProperty(String property, Object value) {
try {
Field declaredField = this.getClass().getDeclaredField(property);
switch (declaredField.getAnnotatedType().getType().getTypeName()) {
case "java.lang.String":
declaredField.set(this, value);
break;
// handle other types
}
} catch (NoSuchFieldException e) {
// handle exception
} catch (IllegalAccessException e) {
// handle exception
}
}
public static void main(String[] args) {
Test test = new Test();
test.setProperty("name", "Bob");
System.out.println(test.name);
}
}
I would not solve this with reflection. If your PlayerCharacter has an enumerable set of attributes, I would model these as a Java enum and store the attribute values within the PlayerCharacter object in an EnumMap:
import java.util.EnumMap;
public class PlayerCharacter {
public enum Attribute {
AGILITY,
DEXTERITY,
/* etc ...*/
VITALITY
}
private EnumMap<Attribute, Integer> attributes = new EnumMap<>(Attribute.class);
public PlayerCharacter() {
// initialize each attribute with a default value (0 in this example)
for (Attribute a : Attribute.values()) {
attributes.put(a, new Integer(0));
}
}
public int getValue(Attribute attribute) {
return attributes.get(attribute);
}
public void levelUp(Attribute attribute, int amount) {
attributes.put(attribute, attributes.get(attribute) + amount);
}
}
The biggest benefit of using an enum instead of plain old String (+reflection), is that this way you get compile-time type safety for the code that's using your PlayerCharacter.
Using Reflection API, you can access the methods and properties on an object at run time. The other answer describes its usage. But I don't recommend reflections for your problem. How about the following:
public void changeHairColor(String variable, String color) {
if("name".equalsIgnoreCase(variable))
this.name = color;
else if("age".equalsIgnoreCase(variable))
this.age = Integer.parseInt(color);
else if("color".equalsIgnoreCase(variable))
this.color = color;
else
throw new Exception ("error - property not available");
}
}
Note, your existing method name 'changeHairColor' doesn't make sense in the context. It should be someething like 'changeProperty' because you are not just changing the 'color', you are changing any available property with this method.

Using the Check class, add the code to have the Checks sorted by checkNumber

Using the Check class, add the code to have the Checks sorted by checkNumber.
import java.util.Date;
public class Check implements Comparable {
private int checkNumber;
private String payTo;
private Date date;
private float amount;
public int compareTo(Object arg0) {
//Insert code here
}
public int getCheckNumber() {
return checkNumber;
}
public void setCheckNumber(int checkNumber) {
this.checkNumber = checkNumber;
}
public String getPayTo() {
return payTo;
}
public void setPayTo (String payTo) {
this.payTo = payTo;
}
public Date getDate() {
return date;
}
public void setDate (Date date) {
this.date = date;
}
public float getAmount() {
return amount;
}
public void setAmount (float amount) {
this.amount = amount;
}
}
My solution is below, but it does not seem to work.
Can anyone help me with the solution?
public int compareTo(Object arg0) {
if(this.checkNumber == arg0.checkNumber)
return 0;
else
return this.checkNumber > arg0.checkNumber ? 1 : -1;
}
You didn't specify what you mean by "doesn't work", but reading your code, I'm assuming you get a compilation error.
The reason for this is because the code you were given has not specified a type for the comparable, so it doesn't know what type you even want to compare it to. It will use Object by default, which does not (by design) know a thing about Check's fields and methods.
The following modification is the best solution:
public class Check implements Comparable<Check> {
public int compareTo(Check arg0) {/* ...*/ }
}
This will force you to compare this to other Check's only and make arg0 a Check object, rendering its fields and methods available to you.
Should the parameters of the problem you were given not allow you to modify the provided code, then the (very very distant) second best solution is:
public int compareTo(Object arg0) {
Check other = null;
if(arg0 instanceof Check)
other = (Check)arg0;
// Other checks.
}
This adaptation would technically work for your problem given the stipulation that you are not allowed to modify the provided code, but is otherwise not at all recommended, as the contract for Comparable wants the type of object you wish to compare against to be specified, and not specifying it can introduce problems.
In fact, I'd say you are fully allowed to tell the person who gave you this problem that they are a terrible person for giving you a problem with this mistake in it, because not specifying a Comparable type is a really bad practice. Especially if they're teaching you how to program.

How to create a variable that can be set only once but isn't final in Java

I want a class that I can create instances of with one variable unset (the id), then initialise this variable later, and have it immutable after initialisation. Effectively, I'd like a final variable that I can initialise outside of the constructor.
Currently, I'm improvising this with a setter that throws an Exception as follows:
public class Example {
private long id = 0;
// Constructors and other variables and methods deleted for clarity
public long getId() {
return id;
}
public void setId(long id) throws Exception {
if ( this.id == 0 ) {
this.id = id;
} else {
throw new Exception("Can't change id once set");
}
}
}
Is this a good way of going about what I'm trying to do? I feel like I should be able to set something as immutable after it's initialised, or that there is a pattern I can use to make this more elegant.
Let me suggest you a little bit more elegant decision.
First variant (without throwing an exception):
public class Example {
private Long id;
// Constructors and other variables and methods deleted for clarity
public long getId() {
return id;
}
public void setId(long id) {
this.id = this.id == null ? id : this.id;
}
}
Second variant (with throwing an exception):
public void setId(long id) {
this.id = this.id == null ? id : throw_();
}
public int throw_() {
throw new RuntimeException("id is already set");
}
The "set only once" requirement feels a bit arbitrary. I'm fairly certain what you're looking for is a class that transitions permanently from uninitialized to initialized state. After all, it may be convenient to set an object's id more than once (via code reuse or whatever), as long as the id is not allowed to change after the object is "built".
One fairly reasonable pattern is to keep track of this "built" state in a separate field:
public final class Example {
private long id;
private boolean isBuilt;
public long getId() {
return id;
}
public void setId(long id) {
if (isBuilt) throw new IllegalArgumentException("already built");
this.id = id;
}
public void build() {
isBuilt = true;
}
}
Usage:
Example e = new Example();
// do lots of stuff
e.setId(12345L);
e.build();
// at this point, e is immutable
With this pattern, you construct the object, set its values (as many times as is convenient), and then call build() to "immutify" it.
There are several advantages to this pattern over your initial approach:
There are no magic values used to represent uninitialized fields. For example, 0 is just as valid an id as any other long value.
Setters have a consistent behavior. Before build() is called, they work. After build() is called, they throw, regardless of what values you pass. (Note the use of unchecked exceptions for convenience).
The class is marked final, otherwise a developer could extend your class and override the setters.
But this approach has a fairly big drawback: developers using this class can't know, at compile time, if a particular object has been initialized or not. Sure, you could add an isBuilt() method so developers can check, at runtime, if the object is initialized, but it would be so much more convenient to know this information at compile time. For that, you could use the builder pattern:
public final class Example {
private final long id;
public Example(long id) {
this.id = id;
}
public long getId() {
return id;
}
public static class Builder {
private long id;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public Example build() {
return new Example(id);
}
}
}
Usage:
Example.Builder builder = new Example.Builder();
builder.setId(12345L);
Example e = builder.build();
This is much better for several reasons:
We're using final fields, so both the compiler and developers know these values cannot be changed.
The distinction between initialized and uninitialized forms of the object is described via Java's type system. There is simply no setter to call on the object once it has been built.
Instances of the built class are guaranteed thread safe.
Yes, it's a bit more complicated to maintain, but IMHO the benefits outweigh the cost.
I recently had this problem when writing some code to construct an immutable cyclic graph where edges reference their nodes. I also noticed that none of the existing answers to this question are thread-safe (which actually allows the field to be set more than once), so I thought that I would contribute my answer. Basically, I just created a wrapper class called FinalReference which wraps an AtomicReference and leverages AtomicReference's compareAndSet() method. By calling compareAndSet(null, newValue), you can ensure that a new value is set at most once by multiple concurrently modifying threads. The call is atomic and will only succeed if the existing value is null. See the example source below for FinalReference and the Github link for sample test code to demonstrate correctness.
public final class FinalReference<T> {
private final AtomicReference<T> reference = new AtomicReference<T>();
public FinalReference() {
}
public void set(T value) {
this.reference.compareAndSet(null, value);
}
public T get() {
return this.reference.get();
}
}
Google's Guava library (which I recommend very highly) comes with a class that solves this problem very well: SettableFuture. This provides the set-once semantics that you ask about, but also a lot more:
The ability to communicate an exception instead (the setException method);
The ability to cancel the event explicitly;
The ability to register listeners that will be notified when the value is set, an exception is notified or the future is canceled (the ListenableFuture interface).
The Future family of types in general used for synchronization between threads in multithreaded programs, so SettableFuture plays very nicely with these.
Java 8 also has its own version of this: CompletableFuture.
You can simply add a boolean flag, and in your setId(), set/check the boolean. If I understood the question right, we don't need any complex structure/pattern here. How about this:
public class Example {
private long id = 0;
private boolean touched = false;
// Constructors and other variables and methods deleted for clarity
public long getId() {
return id;
}
public void setId(long id) throws Exception {
if ( !touchted ) {
this.id = id;
touched = true;
} else {
throw new Exception("Can't change id once set");
}
}
}
in this way, if you setId(0l); it thinks that the ID is set too. You can change if it is not right for your business logic requirement.
not edited it in an IDE, sorry for the typo/format problem, if there was...
Here's the solution I came up with based on mixing some of the answers and comments above, particularly one from #KatjaChristiansen on using assert.
public class Example {
private long id = 0L;
private boolean idSet = false;
public long getId() {
return id;
}
public void setId(long id) {
// setId should not be changed after being set for the first time.
assert ( !idSet ) : "Can't change id from " + this.id + " to " + id;
this.id = id;
idSet = true;
}
public boolean isIdSet() {
return idSet;
}
}
At the end of the day, I suspect that my need for this is an indication of poor design decisions elsewhere, and I should rather find a way of creating the object only when I know the Id, and setting the id to final. This way, more errors can be detected at compile time.
I have this class, similar to JDK's AtomicReference, and I use it mostly for legacy code:
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.NotThreadSafe;
#NotThreadSafe
public class PermanentReference<T> {
private T reference;
public PermanentReference() {
}
public void set(final #Nonnull T reference) {
checkState(this.reference == null,
"reference cannot be set more than once");
this.reference = checkNotNull(reference);
}
public #Nonnull T get() {
checkState(reference != null, "reference must be set before get");
return reference;
}
}
I has single responsibilty and check both get and set calls, so it fails early when client code misuse it.
Here are two ways; the first is basically the same as some others mentioned in other answers, but it is here to constrast with the seconds. So the first way, Once is to have a value that can be set only once by enforcing that in the setter. My implementation requires non-null values, but if you want to be able to set to null, then you would need to implement an 'isSet' boolean flag as suggested in other answers.
The second way, Lazy, is to provide a function that lazily supplies the value once the first time the getter is called.
import javax.annotation.Nonnull;
public final class Once<T>
{
private T value;
public set(final #Nonnull T value)
{
if(null != this.value) throw new IllegalStateException("Illegal attempt to set a Once value after it's value has already been set.");
if(null == value) throw new IllegalArgumentException("Illegal attempt to pass null value to Once setter.");
this.value = value;
}
public #Nonnull T get()
{
if(null == this.value) throw new IllegalStateException("Illegal attempt to access unitialized Once value.");
return this.value;
}
}
public final class Lazy<T>
{
private Supplier<T> supplier;
private T value;
/**
* Construct a value that will be lazily intialized the
* first time the getter is called.
*
* #param the function that supplies the value or null if the value
* will always be null. If it is not null, it will be called
* at most one time.
*/
public Lazy(final Supplier<T> supplier)
{
this.supplier = supplier;
}
/**
* Get the value. The first time this is called, if the
* supplier is not null, it will be called to supply the
* value.
*
* #returns the value (which may be null)
*/
public T get()
{
if(null != this.supplier)
{
this.value = this.supplier.get();
this.supplier = null; // clear the supplier so it is not called again
// and can be garbage collected.
}
return this.value;
}
}
So you might use these as follows;
//
// using Java 8 syntax, but this is not a hard requirement
//
final Once<Integer> i = Once<>();
i.set(100);
i.get(); // returns 100
// i.set(200) would throw an IllegalStateException
final Lazy<Integer> j = Lazy<>(() -> i);
j.get(); // returns 100
try have an int checker like
private long id = 0;
static int checker = 0;
public void methodThatWillSetValueOfId(stuff){
checker = checker + 1
if (checker==1){
id = 123456;
}
}
//u can try this:
class Star
{
private int i;
private int j;
static boolean a=true;
Star(){i=0;j=0;}
public void setI(int i,int j) {
this.i =i;
this.j =j;
something();
a=false;
}
public void printVal()
{
System.out.println(i+" "+j);
}
public static void something(){
if(!a)throw new ArithmeticException("can't assign value");
}
}
public class aClass
{
public static void main(String[] args) {
System.out.println("");
Star ob = new Star();
ob.setI(5,6);
ob.printVal();
ob.setI(6,7);
ob.printVal();
}
}
Marking a field private and not exposing a setter should be sufficient:
public class Example{
private long id=0;
public Example(long id)
{
this.id=id;
}
public long getId()
{
return this.id;
}
if this is insufficient and you want someone to be able to modify it X times you can do this:
public class Example
{
...
private final int MAX_CHANGES = 1;
private int changes = 0;
public void setId(long id) throws Exception {
validateExample();
changes++;
if ( this.id == 0 ) {
this.id = id;
} else {
throw new Exception("Can't change id once set");
}
}
private validateExample
{
if(MAX_CHANGES==change)
{
throw new IllegalStateException("Can no longer update this id");
}
}
}
This approach is akin to design by contract, wherein you validate the state of the object after a mutator (something that changes the state of the object) is invoked.
I think the singleton pattern might be something you should look into. Google around a bit to check if this pattern meets your design goals.
Below is some sudo code on how to make a singleton in Java using enum. I think this is based off Joshua Bloch's design outlined in Effective Java, either way it's a book worth picking up if you don't have it yet.
public enum JavaObject {
INSTANCE;
public void doSomething(){
System.out.println("Hello World!");
}
}
Usage:
JavaObject.INSTANCE.doSomething();

List of enum vs. class of booleans

For now, I have a class with fields.
#Entity
public class Fuel {
#Id #GeneratedValue
private Long id;
private boolean diesel;
private boolean gasoline;
private boolean etanhol;
private boolean cng;
private boolean electric;
public Fuel() {
// this form used by Hibernate
}
public List<String> getDeclaredFields() {
List<String> fieldList = new ArrayList<String>();
for(Field field : Fuel.class.getDeclaredFields()){
if(!field.getName().contains("_") && !field.getName().equals("id") && !field.getName().equals("serialVersionUID") ) {
fieldList.add(field.getName());
}
Collections.sort(fieldList);
}
return fieldList;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public boolean isDiesel() {
return diesel;
}
public void setDiesel(boolean diesel) {
this.diesel = diesel;
}
public boolean isGasoline() {
return gasoline;
}
public void setGasoline(boolean gasoline) {
this.gasoline = gasoline;
}
public boolean isEtanhol() {
return etanhol;
}
public void setEtanhol(boolean etanhol) {
this.etanhol = etanhol;
}
public boolean isCng() {
return cng;
}
public void setCng(boolean cng) {
this.cng = cng;
}
public boolean isElectric() {
return electric;
}
public void setElectric(boolean electric) {
this.electric = electric;
}
}
I think it makes sense, but when I asked another question (maybe a stupid example since there can only be either automatic or manual gearbox) https://stackoverflow.com/questions/11747644/selectonemenu-from-declared-fields-list-in-pojo , a user recommend me to use enums instead. Like this way:
public enum Fuel {
DIESEL("diesel"),
GASOLINE("gasoline"),
ETANHOL("etanhol"),
CNG("cng"),
ELECTRIC("electric");
private String label;
private Fuel(String label) {
this.label = label;
}
public String getLabel() {
return label;
}
}
However, since there exists hybrids on the market (like Toyota Prius) the parent class would implement the boolean class at this way:
private Fuel fuel = new Fuel();
and if using enumerated list at this way:
private List<Fuel> fuelList = new ArrayList<Fuel>();
What is the best practice? Keep in mind that I might have 100 different fuels (just for example =). Do not forget that it is an entity and hence persisted in a database.
Thanks in advance =)
It sounds to me like you want an EnumSet, yes, definitely over a bunch of bool's.
This reminds me a lot of the design patterns for flags and I recently posted an SO question on exactly that: Proper design pattern for passing flags to an object
This supports having 100 different fuel types easily. However it doesn't support a car using 100 different fuel types simultaneously easily. But that to me sounds perfectly fine - it would be very hard to build such a car and this is perfectly reflected in the programmatic complexity of coding this :) (Unless of course it really was just supporting all corn-based fuels - in which you might prefer a polymorphic pattern.)
You should definetly use enums.
Image you want to get the fuel-type of an object.
If you would use bools you would end up with something like this:
if (myClass.IsGasoline())
else if (myClass.IsOtherFuel())
else if
...
If you use enums you can simply do something like:
Fuel fuel = myClass.GetFuelType()
(This is just pseudo-code ;))
If the number of hybrids is low, and I guess it will be better to use Enums, and include hybrids as a different case.
Otherwise you will have to manage the logic in a way that can be cumbersome, as when you set a certain Fuel to true you, most likely, will have also to set to false the current one set to true. I am saying this as you have setters for your fuel categories and you don't only define at construction.
EDIT: the way on how to ask for the type of fuel you are using would also be an argument in favor of enums.

Implementation question regarding base classes and derived classes

I have a question regarding the best way to implement this. I'm going to describe my current implementation and how I seem to have painted myself into a corner:
I have an abstract class called Package:
public abstract class Package {
protected String description;
protected String packagingCode;
protected Dimension dimensions;
protected Weight weight;
protected Package() {
this.description = null;
this.packagingCode = null;
this.dimensions = null;
this.weight = null;
}
protected Package(String description, String packagingCode, Dimension dimensions, Weight weight) throws ShippingException {
this.description = description;
this.packagingCode = packagingCode;
this.dimensions = dimensions;
this.weight = weight;
String exceptionMessage = "";
if(!meetsWeightRequirements()) {
exceptionMessage = "This package's weight exceeds limits. ";
}
if(!meetsDimensionalRequirements()) {
exceptionMessage += "This package's dimensions exceed limits.";
}
if(!StringUtils.isEmpty(exceptionMessage)) {
throw new ShippingException(exceptionMessage);
}
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getPackagingCode() {
return packagingCode;
}
public void setPackagingCode(String packagingCode) {
this.packagingCode = packagingCode;
}
public Dimension getPackageDimensions() {
return dimensions;
}
public void setPackageDimensions(Dimension dimensions) throws ShippingException {
this.dimensions = dimensions;
if(!meetsDimensionalRequirements()) {
this.dimensions = null;
throw new ShippingException("This package's dimensions exceed limits.");
}
}
public Weight getPackageWeight() {
return weight;
}
public void setPackageWeight(Weight weight) throws ShippingException {
this.weight = weight;
if(!meetsWeightRequirements()) {
this.weight = null;
throw new ShippingException("This package's weight exceeds limits.");
}
}
public abstract boolean meetsWeightRequirements();
public abstract boolean meetsDimensionalRequirements();
}
Then I have classes that extend this abstract class like so:
public class WeightBasedPackage extends Package {
public boolean meetsWeightRequirements() {
Weight weight = this.getPackageWeight();
boolean meetsRequirements = false;
if(weight != null) {
meetsRequirements = (weight.getWeight() > 0);
}
return meetsRequirements;
}
public boolean meetsDimensionalRequirements() {
return true;
}
}
I have another object (ShipRequest) that maintains a List of Packages (List<Package>). I also have a services (eg WeightBasedPackageShipService) that uses this object and can access this list of packages. This implementation has worked fine because the services don't really care what type of package it is. The only difference between the packages is the way they implement the abstract methods.
Now here is where the problem comes in. I created a new class:
public class OrderQuantityPackage extends Package {
int quantity;
public OrderQuantityPackage() {
super();
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
public int getQuantity() {
return this.quantity;
}
public boolean meetsWeightRequirements() {
return true;
}
public boolean meetsDimensionalRequirements() {
return true;
}
}
Which has a quantity field. I need to access this field in the service (OrderQuantityPackageShipService). However, since it is of type Package I have to cast it (it seems kinda kludgey).
My question is, how do I implement this in a better fashion (so I don't have to cast) and also ensure type-safety (So that if you are using OrderQuantityPackageShipService, the package must be of type OrderQuantityPackage). I thought about using Generics, but it seems a little to kludgey for what I am trying to do (ShipRequest has a bunch of other attributes and it seemed strange to genericize it based on the type of package).
Thanks.
public abstract class Package {
protected String description; // These shouldn't be private fields instead of protected?
protected String packagingCode; // Nah, I don't think so, otherwise how could I store a value into the Quantity field? =P
protected Dimension dimensions;
protected Weight weight;
protected int quantity;
// Constructors, getters and setters...
public virtual int getQuantity {
throw new NotImplementedException();
}
public virtual int setQuantity(int quantity) {
throw new NotImplementedException();
}
}
public final class OrderQuantityPackage extends Package {
public override int getQuantity {
return super.quantity;
}
public override void setQuantity(int quantity) {
super.quantity = quantity;
}
}
I'm not completely sure about the syntax though, and neither about the NotImplementedException, but I hope you get the idea. So, any Package derived class that needs or require a quantity may do so by overriding the getter and setter of the Quantity property.
No exception should be thrown as of where the Quantity won't be required, it shouldn't get called, so no exception shall be thrown. Furthermore, it testifies that your model only does what it is required when times come.
In addition to it, OrderQuantityShipService shouldn't require a Weight property within the OrderQuantityPackage, and as written by Vivin, one could access the weight anyway.
Otherwise, a simple cast within your service should do it. It is no dirty way to go to use casting. For instance, one must cast the sender object within an event handler to the proper control type he wishes to check for name, state or other property values! The most general class is then passed on to the event, and one must cast... And this, that is not me who said to opt this way, these are software engineers!...
EDIT Vivin, how do one cast from a data type to another in JAVA, is it as in C/C++/C# ?
CastedType variable = (CastedType)TypeCast;
Short Answer: Dependency Inversion
You have a OrderQuantityPackageShipService class that requires certain features from the objects that it processes. So OrderQuantityPackageShipService should be the one specifying those requirements. Typically this is done with an interface. If it is very specific to the service, create the interface nested. ie:
class OrderQuantityPackageShipService {
//...
interface QuantityPackage {
int getQuantity();
// ...
}
}
if it can be used in a consistent manner by other services, define it outside of the OrderQuantityPackageShipService class.
Then have certain packages implement that interface...
Maybe you should create an abstract service and extend it for the different kinds of packages to handle. You could have the handling method be abstract and have each kind of service know what to do with the corresponding package. If you're not to mix types of packages then this might work.
One thing I can think of is why would you need to access the quantity attribute in the class OrderQuantityPackageShipService ? As I look at it you have a getter and setter for each attribute of the class Package. Are these getters and setters really needed ? Having getters/setters for all those attributes doesn't go well with encapsulation.
Can you think of providing public methods in Package class that operate at a higher level and don't expose the internal attributes ? Wouldn't that help ?

Categories