Instantiating objects whose subclass will depend on user input - java

Please excuse the silly questions, I'm fairly new to Java and OOP and I'm trying to follow the Design patterns (avoiding ifs, switches, etc) but I'm having a hard time doing so.
So, I'm building a weapon vendor for a 'game' project of my own. This vendor has a list of objects. These objects are all different instances of the Weapon Superclass (e.g. Sword, Spear, Axe, etc).
When a user tries to buy a weapon, the vendor will show the weapon list and the user selects one by inputting its list index.
I'm now facing two problems:
1) How can I make an instance of an object whose subclass will depend on user input?
2) How can I invoke the right constructor, passing the same parameters of the weapon bought to the new object to be instantiated? I'm trying to do this in the most polymorphic way possible, avoiding ifs and switch statements.
So far, what I tried was making an Interface (iWeapon). Then, based on that interface I made a Factory that receives the type of a weapon (String) and returns a new instance of a weapon with the corresponding subclass.
This allowed me to instantiate a 'generic' weapon using the data type of the interface. However, I don't know if this is the optimal way of achieving this. Also, I don't know how to initialize the attributes of the new instance with the same values of the recently bought weapon, in a polymorphic way.
I tried creating a method 'getAttributesFromOtherWeapon' on all my weapon subclasses, that receives an object with the same types and simply copies these values. The problem I'm facing now is that the iWeapon type object I instantiate doesn't have this method, and if I include it on the interface I get an error on my subclasses saying that 'Class must either be declared abstract or implement abstract method '
My vendor code does something like this:
Weapon weaponToBuy = (Weapon) weaponList.get(weaponChosenIndex);
iWeapon newWeapon = weaponFactory.getWeapon(weaponToBuy.type);
newWeapon.getAttributesFromOtherWeapon(weaponToBuy);
However, since newWeapon is an iWeapon I needed to declare getAttributesFromOtherWeapon on its interface, which looks like this:
public interface iWeapon {
void getAttributesFromOtherWeapon(iWeapon iWeapon);
}
And now, in every Weapon subclass where I try to implement this method I'm require to pass an iWeapon instead of the corresponding Subclass type (Sword, Spear, etc.). Problem is that in my iWeapon interface I didn't define all the attributes corresponding to a Weapon (or any Weapon subclass) since I understand they'd be defined as constants.
I think there's probably an out of the box solution to this that I'm not seeing due to me being a noob on Java. Any help will be thoroughly appreciated

There are various solutions to this.
1. Use generics
interface Weapon<T extends Weapon> {
public Weapon getAttributesFromOther(T t);
}
class Axe implements Weapon<Axe> {
#Override
public Weapon getAttributesFromOther(Axe other) {
// TODO get those attributes
return this;
}
}
... etc.
Pros
Sword#getAtributesFromOther will only take a Sword, if the class is defined as implements Weapon<Sword>.
Cons
If by mistake, you declare something like class Dagger implements Weapon<Pitchfork>, then the getAttributes will take a Pitchfork.
Negligible in my opinion, as it's all compile-time, but worth considering.
Also your weapon references should change to Weapon<?> for unknown weapon types at runtime.
2. Declare a WeaponProperties class extending some parametrized Map, and a getter/setter pair in the Weapon interface
Pros
This will work granularily with all weapons, you just have to check whether the property is present.
You can easily merge properties common to multiple types of weapons.
Cons
Lots of boilerplate in all weapons, lots of "safety" code when copying properties from different weapon types if you allow that.
3. There probably is something even better - will edit if I have an idea
Notes
Make sure to follow Java code conventions, e.g. there's nothing wrong with Hungarian notation, but every type should always be CamelCase (contrary to variable names which are camelBack). This is about your iWeapon interface, which you can easily just refactor to Weapon - see example above.
Afterthought: I realized the getAttributes... methods in my example return Weapon, but that's not relevant to this case - you can safely return void instead

Related

Understanding relationship between Java Super and Sub class constructors and methods

This may be a bit general and I apologize if it is too much so. It pertains to an assignment for a college class and as such would like to focus on my understanding of the topic as opposed to what the answer should be.
As I understand the situation:
I have one parent class called pet, and two subclasses called Dog and Cat. The UML class Diagrams specify that Pet contains the methods createPet(), updatePet(), and petCheckIn().
petCheckIn() requires the ability to create an object if it isn't already, and update one if it is.
The two subclasses contain default constructors, as well as setters and getters for their attributes, but nothing else specific to them.
I don't believe there would be an instance when a Pet object would be needed as the pets being checked in would always be dogs or cats. If constructors are not inherited by the subclasses but methods are, and createPet() is not strictly speaking a constructor, can an inherited method perform the constructor function if designed properly? I feel the implementation should be something like (not concerned about exact syntax as much as I am my understanding of what can and cant be done here):
My pseudocode :
Execute Dog/Cat inherited petCheckIn()
IF new pet THEN
Execute Dog/Cat inherited createPet()
ELSE
Execute Dog/Cat inherited updatePet()
This is an entry level programming class, and so I cant imagine that the implementation would be terribly complex.
Likely I am misunderstanding something/overcomplicating.
Regardless, Thanks for your time.
EDIT:
Truly sorry I never got back to you #Karam and #Chung. Life hits like a freight train sometimes lol. Specifying another class was out of scope for the assignment (though most of what I wanted to know seems to have been as well), nothing was specified about the signature (thats methodName + its arguments correct?). Ultimately I believe a lot depends on how the classes would be implemented by the overall program which was not covered in detail. I can pretty confidently say I was just asking questions that were beyond what was intended at that stage of the lesson plan. I wound up using a parametered constructor in the super class, and another in the subclass which passed arguments for superclass fields to the superclass constructor, then initialized the subclass specific fields. Karam, I never wound up actually defining the methods by which the constructors were called, and wasnt able to educate myself on design patterns, but a relative of mine also mentioned an abstract factory. Id say that is likely the best way to handle it. Unfortunately I do not have more time to dig into this right now so Im calling it good.
Cant tell yall how much I appreciate your willingness to help.
Dog.java constructor:
//Overloaded Constructor that passes parameters to Superclass
constructor.
//TODO: Reconsider which fields need a parameter and which can be set to
default at this point in the program.
//TODO: Verify that not passing an argument for catSpace will default to
-1.
//FIXME: Is dogSpaceNBR known at this point in program?
public Dog(int dogSpaceNBRInput, double dogWeightInput, boolean
groomingInput, String petTypeInput, String petNameInput, int petAgeInput,
int dogSpaceInput, int catSpaceInput, int daysStayInput, double
amountDueInput) {
// Passes arguments common to all pet subclasses to superclass
constructor.
super(petTypeInput, petNameInput, petAgeInput, dogSpaceInput,
catSpaceInput, daysStayInput, amountDueInput);
//Dog specific variables
dogSpaceNbr = dogSpaceNBRInput;
dogWeight = dogWeightInput;
grooming = groomingInput;
}
If i understand well your question , you want to be able to create different instances of your pet depending on the subclass using only methods
There is a Design Pattern called Abstract Factory , it is used to ignore the creation of different methods in a concret way
Example :
You have the class Pet ( it should be abstract ) that contains the method createPet() {}
In your sublcass , you'll have to simply redefine the method createPet() { return new Dog() ; /* or */ return new Cat() ;}
This helps you whenever you create a new sublcass , to redefine the methods without changing in the original class , and this will goes not only for the method createPet() but for all your methods

How do I write a method that has the same implementation for multiple kinds of objects (Java)?

I am writing a (currently) String-based Pokemon game in Java. With the structure I have, there are currently 2 kinds of objects that I want to do Type matchups for: Pokemon and moves. The method I want to write (isStrongAgainst()) would be the same for both. For example, a water type pokemon and a water type move are strong against fire type Pokemon, but these comparisons can imply different things based on context. Both classes have differently implemented isType() methods.
The idea I had was to use an interface that implements a default isStrongAgainst() method and declares an abstract isType() method. I would think that since any class that implements this interface would have to implement isType(), I could use it in my isStrongAgainst(), but I cannot. Is there any way around this or a better suggestion given my problem?
public interface TypeMatch<T> {
boolean isType(Type t);
default boolean isStrongAgainst(Pokemon opponent){
if(T.isType(Type.NORMAL)){
return false;
}
if(T.isType(Type.WATER)){
return opponent.isType(Type.FIRE) ||
opponent.isType(Type.ROCK) ||
opponent.isType(Type.GROUND);
} //etc...
As far as understand, your game contains different behaviors according to type of a Pokemon. I highly recommend you to use strategy design pattern.
What I think is that the isStrongAgainst() function can be refined more.
It would better to make an implementation of isType() in such a way that it returns true if the opponent is weaker than us.
This can then be used in the function isStrongAgainst() directly in its return statement.
Best
PS: I am in class right now and I will give a more detailed answer after I’m over with it, till then if possible try to get some idea of what I have said.
You may:
define Pokemon as an abstract class to implement TypeMatch
move isStrongAgainst(Pokemon opponent) from TypeMatch to Pokemon.
any class that extends Pokemon has the same implementation of isStrongAgainst(Pokemon opponent)

Usage of Generics in Java [duplicate]

Getting into a little bit of confusion here when to use generics. I've looked at Java Generics? but still have a few questions.
Say I have:
public class Honda implements ICar(){
}
public class Opel implements ICar(){
}
Should I use:
public class Person{
ICar car;
.
.
public Person (ICar c){
car = c;
}
}
or
public class Person<T extends ICar>{
T car;
.
.
public Person(T c){
car = c;
}
}
or does it depend on the tasks performed?
Are generics only for aggregation relationships (containers etc); that is, are they just used for collections?
A person is generally not parameterized with a type of car. Only very annoying persons are defined by their car. Persons change cars too (in time). So I would not parameterize the class, if only for the semantics.
Think about what you try to mimic from the real world, before going into such programming details.
The distinction isn't always clearcut but here are a few clues:
Try to think of them as "type parameters" (Which they are.) They are associated with the class but they're not necessarily related to it. (Look at the collections framework for example.)
Type parameters can only be used if they don't change throughout an object's lifetime. This sounds quite obvious, but it's a very handy rule to decide when NOT to use generics. (Example is a person who can change cars.)
On the other hand, if not many instances will use the type parameter, if it's too optional, that's not a good idea either. (A lot of people might not have cars at all.)
And finally, a general thought that I found really useful: if you're unsure, don't be afraid to prototype it. Write the code both ways and check which one looks simpler and easier to comprehend. Show it to someone else without any explanations or maybe wait a day or two and then re-read the code yourself. Then throw the other one away. Throwing away code is good.
You need the generics version if you have any methods that take or return anything involving a T, or if it's possible for other people to access your car field. (Since you didn't show any methods, we can't really tell.)
For example, with the generics version you can have a method like T someMethod();, then when someone has a Person<Honda>, they know they can get a Honda back when they call someMethod, rather than some unknown type of car if you didn't have generics.
Similarly, with the generics version you can have a method like void anotherMethod(T anotherCar);, then when someone has a Person<Honda>, this forces them to pass a Honda to this method, instead of any car.
So basically, having a generic class allows you to place constraints on uses of the object later on (method calls etc.). If the constructor is the only place that you use T, and you don't need to use T in any methods or fields, then yes, there is no point for it.
This has to do with using Inheritance versus Composition.
Without knowing any other semantics, Composition seems more relevant. A person may change cars, without becoming a different person.
http://www.artima.com/objectsandjava/webuscript/CompoInherit1.html
http://en.wikipedia.org/wiki/Composition_over_inheritance
I'd tend to favor composition (what you're calling dynamic binding), especially in the case you use. A person is not a type of ICar, so using the generics here is kind of weird (to me anyway). I'd use generics as a way of saying "A container for ICar", as in Garage although in that case I might just use a collection type as a variable, or extend the collection type if really needed.
I'd suggest to focus on semantics first:
Providing that you may have a Bmw and a Toyota classes implementing the ICar interface, then make this question: can a Person change his car or would it be a different person if he does so?
The generics approach will force you to create a new Person instance if for some reason you need to change the value of the car attribute from Toyota to Bmw in an existent person instance and thus, this new person will be different from the previous one. Of course, you could create the first Person instance as Person<ICar> instead of hooking it to a specific car class but, why use generics then?

When should I use generics to define relationships between types?

Getting into a little bit of confusion here when to use generics. I've looked at Java Generics? but still have a few questions.
Say I have:
public class Honda implements ICar(){
}
public class Opel implements ICar(){
}
Should I use:
public class Person{
ICar car;
.
.
public Person (ICar c){
car = c;
}
}
or
public class Person<T extends ICar>{
T car;
.
.
public Person(T c){
car = c;
}
}
or does it depend on the tasks performed?
Are generics only for aggregation relationships (containers etc); that is, are they just used for collections?
A person is generally not parameterized with a type of car. Only very annoying persons are defined by their car. Persons change cars too (in time). So I would not parameterize the class, if only for the semantics.
Think about what you try to mimic from the real world, before going into such programming details.
The distinction isn't always clearcut but here are a few clues:
Try to think of them as "type parameters" (Which they are.) They are associated with the class but they're not necessarily related to it. (Look at the collections framework for example.)
Type parameters can only be used if they don't change throughout an object's lifetime. This sounds quite obvious, but it's a very handy rule to decide when NOT to use generics. (Example is a person who can change cars.)
On the other hand, if not many instances will use the type parameter, if it's too optional, that's not a good idea either. (A lot of people might not have cars at all.)
And finally, a general thought that I found really useful: if you're unsure, don't be afraid to prototype it. Write the code both ways and check which one looks simpler and easier to comprehend. Show it to someone else without any explanations or maybe wait a day or two and then re-read the code yourself. Then throw the other one away. Throwing away code is good.
You need the generics version if you have any methods that take or return anything involving a T, or if it's possible for other people to access your car field. (Since you didn't show any methods, we can't really tell.)
For example, with the generics version you can have a method like T someMethod();, then when someone has a Person<Honda>, they know they can get a Honda back when they call someMethod, rather than some unknown type of car if you didn't have generics.
Similarly, with the generics version you can have a method like void anotherMethod(T anotherCar);, then when someone has a Person<Honda>, this forces them to pass a Honda to this method, instead of any car.
So basically, having a generic class allows you to place constraints on uses of the object later on (method calls etc.). If the constructor is the only place that you use T, and you don't need to use T in any methods or fields, then yes, there is no point for it.
This has to do with using Inheritance versus Composition.
Without knowing any other semantics, Composition seems more relevant. A person may change cars, without becoming a different person.
http://www.artima.com/objectsandjava/webuscript/CompoInherit1.html
http://en.wikipedia.org/wiki/Composition_over_inheritance
I'd tend to favor composition (what you're calling dynamic binding), especially in the case you use. A person is not a type of ICar, so using the generics here is kind of weird (to me anyway). I'd use generics as a way of saying "A container for ICar", as in Garage although in that case I might just use a collection type as a variable, or extend the collection type if really needed.
I'd suggest to focus on semantics first:
Providing that you may have a Bmw and a Toyota classes implementing the ICar interface, then make this question: can a Person change his car or would it be a different person if he does so?
The generics approach will force you to create a new Person instance if for some reason you need to change the value of the car attribute from Toyota to Bmw in an existent person instance and thus, this new person will be different from the previous one. Of course, you could create the first Person instance as Person<ICar> instead of hooking it to a specific car class but, why use generics then?

Find info about class in java, software design?

I have a bunch of classes extending an abstract Base class.
Each subclass takes an array as in the constructor, (different length depending on class).
These classes could be written by other people.
What is the best way to figure out the length of the array the class needs?
I could:
(A) Require that each derived class have a static method, returning the length.
However, the base class cannot enforce this, since abstract static methods does not work in java.
(B) Each derived class have a constructor with no arguments, and I construct
such classes just to be able to call the countParameters() method, that
I can enforce from the Base class. This feels "cludgy", since I am not interested in creating such object, but only need some info about it.
The reason is that I am creating a GUI, that gives the user the ability to create
instances of Derived classes, but each Derived class takes different number of parameters.
That is, I need to know how to draw the GUI before I can create the classes.
EDIT:
I could just require that each Derived class have a private
constructor, with no arguments, and using reflection I can call the countParameters() method.
EDIT2: Actually, what I am interested in, is what the names of the parameters are.
That is, if the class Derived have the constructor
public Derived(double name1,double name2,...)
I need a way to generate the String[] array
{name1,name2,...}
I guess this would be impossible to do without creating an instance of the class,
but for the user to be able to create such class, he/she needs the parameter names!
Moment 22.
It sounds like you need the Factory Pattern.
In general, it's a bad idea for a base class to know the set of it's descendant's. So you define another class whose job it is to know that.
If you have something like a Shape, with ThisShape and ThatShape as derived classes, then a ShapeCreator will handle the job of creating the specific set of shapes your program supports, giving each one the arguments it needs.
It's not quite clear what you're trying to achieve, but I wonder: Do the subclasses really have to take a single parameter with an array, as opposed to a list of parameters?
Constructor<?> ctor = Test.class.getConstructors()[0];
int parameterCount = ctor.getParameterTypes().length;
ctor.newInstance(new Object[parameterCount]);
how about this code:
public absract Base {
public abstract int size();
public Base(Object[] objs) {
if (objs.length != size()) {
throw new IllegalArgumentException();
}
//rest of your code.
}
each child class needs to implement size method.
hope its help.
I'd go with method A. You can't get the compiler to enforce the existence of such a method, but you can certainly enforce it in your program - no method, no work!
Seriously, this whole scheme is a bit brittle and I can't think of a way to make it significantly better. An incorrect implementation of those subclasses will bomb out, that's life.
A possible remedy would be for you to provide a set of interfaces for those subclasses, such as
SubClassTaking2Args
SubClassTaking3Args
...
and requiring your sub's to implement one of those as a marker interface. But that's just more bureaucracy with little more effect.

Categories