How do I check which subclass was passed into a constructor? - java

I am relatively new to Java and programming, so I apologize if this question seems stupid. I am creating a battle-game for a Java programming class -- I have a Hero class with some basic methods and a subclass Paladin that extends Hero but with its own unique methods added in. I want to have a Battleground object that passes in ANY Hero class but then check which specific subclass was passed in. How do I determine which of the Hero subclasses were passed in?
public class Hero {
private String name;
private int hitPoints;
public Hero (String name, int hitPoints) {
this.name = name;
this.hitPoints = hitPoints;
}
public String getName() { return this.name; }
public int getHitPoints() { return this.hitPoints; }
public void takeDamage(int amount) { this.hitPoints -= amount; }
}
And here is the Paladin Class
public class Paladin extends Hero {
public Hero (String name, int hitPoints) {
super(name, hitPoints);
}
public void heal(int amount) {
this.hitPoints += amount;
}
}
So in the battleground class, I have a method that attempts (incorrectly) to check if the hero passed in is a Paladin. How would I go about doing this? The if statement is a placeholder psuedo-code just to clarify what I mean.
public class Battleground {
private Hero player;
public Battleground (Hero player) {
this.player = player;
}
public void startRound() {
// HERE!!
if (player.equals(Paladin)) {
player.heal();
}
}
}

Thinking in terms of what your classes are actually modelling, it doesn't make much sense for a battleground to know that a Paladin heals themselves at the start of a round, nor for the battleground to be responsible for making sure the Paladin heals themselves.
A more sensible design would be for the game to inform the hero that the round has started, and let the particular Hero subclass control what that kind of hero does when the round starts. For example:
public class Hero {
// ...
public void onRoundStart() {
// do nothing
}
}
public class Paladin extends Hero {
// ...
#Override
public void onRoundStart() {
// your heal method takes an int as its argument
heal(10);
}
}
public class Battleground {
// ...
public void startRound() {
// let the particular Hero subclass control what happens
player.onRoundStart();
// ...
}
}
This way you don't need any if statements or instanceof checks, but also the code defining a Paladin's behaviour is in the Paladin class where it sensibly belongs. If you want to change the rules for Paladins later, it will be easier to know which class you need to edit.
This kind of refactoring is called "replace conditional with polymorphism".

Using Instanceof is Considered a Code Smell Sometimes
Using instanceof can be considered to be a code smell - which means a bad practice.
There is an alternative for you to consider.
Add the heal() method to the Hero class, but leave the implementation blank.
Put only an implementation in the Paladin class. Then, even though heal() will be called on all players, it will only do something inside Paladins.
However... if you still need to detect the class type...
Ways to Detect the class
There are multiple ways to differentiate between classes.
Instance of is one.
Another is having different constructors.
A third is having an ENUM or String field called EntityType.
In your case, I think instanceof or using a special field make the most sense.
Instanceof
if(player instanceof Paladin)
Using a Special Field
Quick Example Hero
public class Hero {
private String name;
private int hitPoints;
private int HeroType;
public Hero (String name, int hitPoints) {
this.name = name;
this.hitPoints = hitPoints;
this.heroType = BASIC_HERO;
}
public static int BASIC_HERO = 0;
public static int PALADIN_HERO = 1;
...
}
Quick Example Paladin
public class Paladin extends Hero {
public Paladin(String name, int hitPoints) {
super(name, hitPoints);
this.heroType = PALADIN_HERO;
}
}
Detecting the Type
You would have a method in both classes called getHeroType().
if(hero.getHeroType == Hero.PALADIN_HERO){
}else if(hero.getHeroType == Hero.BASIC_HERO){
}

If you want, you can use to check the class of the object:
if (player instanceof Paladin)
No question, this will work. If you don't have a lot of "special" behaviour and a limited small amount of cases, that can be a reasonable solution. But assuming that your game will end up with a lot of special handling for each subclass of Hero and probably not only in the startRound() method of your Battlefield class, your code will someday be cluttered with these instanceof checks. Same applies, if you use a specific type field within the Hero class.
In that case a better solution might be to relocate the logic into special classes and try to avoid type checks if possible or at least have a well defined place for them, if necessary.
Update: removed faulty demo implementation

You can always do player.getClass to get actuall class. As for if statements you can use instanceof operator.
So
if (player instanceof Paladin) {
((Paladin)player).heal();
}

Related

Java OOP instance of class

I have following classes structure extention:
Entity > Creature > (abstract)Player > Mage.
In Mage class I implement interface iCastable with method castSpell(). In main method I create new Mage(...).
Problem is that when I send it as a prop of Player class someMethod(Player player), I cannot use methods implemented from interface iCastable. I can only use methods from Creature class via player.getCreaure.whaterver() because Player extend it. How can I solve that issue?
I do not want to send it as a prop of Mage class, because I want to use all my other classes like Warrior for example. I also want to avoid player instanceof Mage, because if I had 1000 classes I must do 1000 check for every method. Do you have any ideas how to solve that?
EDIT added code
public class Creature extends Entity {...}
public abstract class Player extends Creature {
public Player(String name) {
super(name);
}
public abstract void attack();
}
public class Mage extends Player implements iCastable {
...
#Override
public void castSpecial() {...}
}
public static void main(String[] args) {
Mage mage = new Mage("Mage");
Duel duel = new Duel(mage, monsters);
}
public class Duel {
private Player player;
...
public Duel(Player player, ArrayList<Monster> monsters) {
this.player = player;
...
}
private void castSpecial() {
// error here
player.castSpecial();
}
}
I am trying to do something like player.getInstanceClass(mage, warrior or whatever).cashSpecial()
Your method can be written like this:
private void castSpecial() {
if (player instanceof iCastable) {
((iCastable) player).castSpecial();
}
}
The instanceof performs a runtime check to see if the Player instance has the correct subclass. If the check succeeds then the type cast will also succeed. (If you do the type cast without a "guard", then it will throw an ClassCastException if the player doesn't have the required type.)
Obviously, if the player does not have spell casting ability, the method does nothing.
Note: the interface name iCastable is wrong from two perspectives.
A class or interface name should never start with a lowercase letter.
The name is wrong. ICastable implies that you would "cast" a Mage. In fact, the Mage is the subject, that casts the spell, not the spell that is cast. A better name might be ISpellCaster.

Reuse validation method. Convert object

I have two similar class objects. I have a couple of methods for the first class object wich I also want to reuse for my second class object but I'm not sure how and I don't want to write duplicate methods.
I extracted and simplified an example to show how i think.
first class
public class FirstClass {
int number;
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
...
}
Second class
public class SecondClass {
int number;
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
...
}
Third class
public class Main {
public static void main(String[] args) {
FirstClass firstClass = new FirstClass();
firstClass.setNumber(5);
SecondClass secondClass = new SecondClass();
secondClass.setNumber(5);
numberIsFive(firstClass);
numberIsFive(secondClass);
}
public void numberIsFive(Object myObject){
if(myObject instanceof FirstClass){
myObject = (FirstClass)myObject;
}else if(myObject instanceof SecondClass){
myObject = (SecondClass)myObject;
}
if(myObject.getNumber() == 5){
System.out.println("is five");
}else{
System.out.println("is not five");
}
...
}
}
and no numberIsIFive(firsclass.getNumber()) is not an option since the methods I use have much more validations.
thanks in advance
For this case that might be "over-engineering", but in general you would look towards composition here, like:
interface IntValueHolder {
int getNumber();
void setNumber(int value);
}
class IntValueHolderImpl implements IntValueHolder { ...
And then you would "drop" the code that you currently have in both of your classes, and instead, both classes would (somehow) have an instance of IntValueHolder.
In your case, it might be more appropriate to simple have your two classes implement that "common" interface IntValueHolder - to at least avoid that repeated instanceof calls and downcast (down to a specific class).
Edit: of course, another option would be to use inheritance here - make your two classes derive from some base class that provides this behavior. But using inheritance just to avoid code duplication is most of the time a bad idea. Classes inherit from each other because that makes "sense" in the underlying model, not to save a line of code.
Before continuing I recommend you to read about it and other object oriented programming concepts by yourself.
Focusing on this particular case, you should create a base class such as
public class BaseClass {
int number;
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
}
Which includes all common fields and methods of your FirstClass and SecondClass. Then remove those methods from your two current classes, and just create them as public class FirstClass extends BaseClass to give them BaseClass functionality.
Finally, you'd have to change your validation method, to only accept objects that belong to your base class by making it like this public void numberIsFive(BaseClass myObject) (as a general rule you'll have much less errors by accepting a specific class in a method, rather than accepting any old object).
Edit: Other answerers are correct and Inheritance is also a valid solution. Which one you use would depend on what makes more sense in the context of your application.
You should create an interface and apply it in both classes, then make your validation method receive an interface instead of an Object
Example:
public interface Number {
int get();
void set(int n);
}
Then your classes will look like this:
public class FirstClass implements Number {
int number;
#Override
public int get() {
return number;
}
#Override
public void set(int n) {
this.number = n;
}
}
And your validation method receives a Number:
public void numberIsFive(Number myNumber){
...
}

Making methods only accessible to child classes, not instantiated objects

public class Flight{
private int flying = 0;
public boolean fly() {
flying = 1;
return isFlying();
}
private isFlying(){
return flying > 0;
}
}
public class CargoFlight extends Flight{
public boolean startFlight(int passengers)
if (passengers <= 0){
return false;
}
return fly(); // Want to be able to do this
}
}
public class Airport{
public static void main(){
CargoFlight f1 = new CargoFlight();
f1.fly(); // Don't want to be able to do this
}
}
f1 has the property fly(), is there any way to restrict it such that the method fly() can be called inside the body of the classes extending Flight (like CargoFlight here), but cannot be called using the instances of the subclasses (like f1)? I have added comments to the code to make it clear.
The nearest access specifier to what you want is protected. However, protected members are still always accessible to other classes in the same package, so it won't prevent access from your Airport class.
If you really need the subclass to block access to the method except to the subclass, then you can override it in the subclass to always throw an exception, then use super to invoke the original method:
public class Flight {
private int flying = 0;
protected boolean fly() {
flying = 1;
return isFlying();
}
private boolean isFlying() {
return flying > 0;
}
}
public class CargoFlight extends Flight {
#Override
protected boolean fly() {
throw new IllegalAccessError();
}
public boolean startFlight(int passengers) {
if (passengers <= 0) {
throw new IllegalArgumentException();
}
return super.fly();
}
}
The flaw with any solution though, is that it violates the Liskov substitution principle. A CargoFlight is no longer a proper instance of Flight because it doesn't have the normal fly method that other Flights have. If you intend fly only to be called by subclasses and never directly, then it's okay (although you should document that rule in the method Javadoc), but it still leaves you without the nicety of having a polymorphic method to call to tell generic Flights to fly.
A nicer solution, if it can fit with your design, would be to have fly and startFlight be the same method (that means same name and same arguments, and the same return type or a subtype), so then the subclass method could simply override the base implementation. The only method outside callers would see is fly. That means that your passengers argument either needs to be part of the base method Flight.fly too, or, remove it from both method implementations and make it into a separate property setPassengers for those subclasses that need it:
public class CargoFlight extends Flight {
private int passengers = 0;
public void setPassengers(int p) {
passengers = p;
}
#Override
public boolean fly() {
if (passengers <= 0) {
throw new IllegalStateException(); // or whichever
}
return super.fly();
}
}

Having a method accept different objects as an argument

First I will just put my sample code.
public class Shape {
public String colour;
public Shape(String colour) {
this.colour = colour;
}
}
public class Car {
public String colour;
public Car (String colour) {
this.colour = colour;
}
}
public class Colour {
public static String getColour(Object item) {
return item.**colour**;
}
}
I've read other questions related to this, but I just can't seem to understand. I found their original code was just too complex for me to get around. So I tried to make as simple a code as possible. Anyway, I want getColour to accept both the Shape and Car object. If I use Object like I did in my example, the "colour" in bold is considered an error. The error I get is "colour cannot be resolved or is not a field". What's wrong?
Also, I've heard a lot of "static methods are bad" etc., is this a case of it being bad? Because I find if I don't make it static, then I need to duplicate getColour methods in both the Shape and Car classes. If I should avoid static methods, then please suggest another way to do this.
What you're looking for is the concept of interfaces:
public interface Colourable {
String getColour();
void setColour(String colour);
}
You should modify the Shape and Car classes:
public class Shape implements Colourable {
public Shape(String colour) {
this.colour = colour;
}
private String colour;
public String getColour() {
return colour;
}
public void setColour(String colour) {
this.colour = colour;
}
}
(note that I've made the colour field private; this is common practice and called encapsulation)
You can then define your static method as
public static String getColour(Colourable item) {
return item.getColour();
}
And static methods are definitely not bad, though in this case the method itself is a bit superfluous, because if you already have an Colourable, you know you can call .getColour() to get its color. A bit more useful would be the method
public static boolean isRed(Colourable item) {
return "red".equals(item.getColour());
}
You can "unify" Shape and Car. There are two general approaches:
Inheritance and
Interfaces
Let's look at both.
Inheritance: When a class Porsche inherits (or, in Java syntax, extends) a class Car, you establish an "is-a" relationship. In this case: Porsche is-a Car. Now, the magic comes to work, when you use object references. You can now write something like this:
Car c = new Porsche();
Since a Porsche has everything, a Car has (plus some things on top), you can see a Porsche as a Car (each Porsche is a Car, but not each Car is a Porsche). Reading my last sentence carefully, it is obvious, that the following does not work and, in fact, produces a compile error:
Porsche p = new Car();
What you can now do is write a method, that expects a Car and pass in a Porsche (since every Porsche is a Car).
Coming back to your example. To get this working, you could define a common parent class for Shape and Car, let's call it Colourable and give it a method public Colour getColour(). Then, you could simply change your getColour(Object item) method to getColour(Colourable c).
Remeber the thing I said about the "is-a" relation? Ask yourself: is each Shape a Colourable? Is each Car a Colourable? Why should Car and Shape both be in the same bucket (Colourable)? And what to do, if Car already has a parent class, e.g. Vehicle? This solution is sub-optimal.
Interfaces: This is, where interfaces come into play. Interfaces guarantee, that certain methods are present. Instead of defining a common parent class Colourable, you could simply write Colourable as an interface, containing the method public Colour getColour(). Now Shape and Car can implements this interface. This forces you to implement this method in both classes. The beauty: you can use interfaces just like classes. Meaning your implementation of getColour(Colourable c) does not need to change.
For more details, please read the provided tutorials on Inheritance and Interfaces.
Seems like your trying to use duck typing, which isn't how Java works.
The easiest thing to do, IMHO, would be to define an interface to handle the color. E.g.:
public interface Colourful {
public String getColour();
}
public class Shape implements Colorful {
private String colour;
public Shape(String colour) {
this.colour = colour;
}
#Override
public String getColour() {
return colour;
}
}
public class Car {
private String colour;
public Car (String colour) {
this.colour = colour;
}
#Override
public String getColour() {
return colour;
}
}
Alternatively, if you don't want to change Shape and Car, you could use reflection to extract the colour field, but this is usually considered a bad idea, and you'd probably be better off not using it:
public static String getColour(Object o) {
Field colourField;
try {
colourField = o.getClass().getField("colour");
} catch (NoSuchFieldException e) {
// No such field
return null;
}
Object colourValue;
try {
colourValue = colourField.get(o);
} catch (IllegalAccessException e) {
// The field isn't public
return null;
}
if (!(colourValue instanceof String)) {
// The field isn't a String
return null;
}
return (String) colourValue;
}
The reason an error is thrown is that Object doesn't have a colour field. I wouldn't recommend it, but if you want to move forward with this design, you could make a class called ShapeCarParent (used in this case because I see no clear relationship between the two) and have both the classes inherit from that, and then change getColour, like so:
public class ShapeCarParent{
public String colour;
}
public class Car extends ShapeCarParent
public class Shape extends ShapeCarParent
public class Colour {
public static String getColour(ShapeCarParent item) {
return item.colour;
}
}
This is still pretty poor style, so you can also use an interface which you then implement in each class.
public interface ColorProperties{
public String getColour();
}
public class Car implements ColorProperites{
public String getColour() {
return colour;
}
}
public class Shape implements ColorProperites{
public String getColour() {
return colour;
}
}
Hope this helps.

OO - Creating object using a method of no argument

I am experience some problems in understanding how the OO pattern works, My lecturer gave me the following question but I cannot solve it after thinking whole day
Scenario for my problems.
There is a class named "ShapeManager" which manages the Shape object. A class named "Shape" has two subclasses named "Circle" and "Rectangle"
The implementation of Shape class as follow
abstract public class Shape {
private String id;
private double length;
public Shape() {
}
public Shape(String id , double length) {
this.id = id;
this.length = length;
}
public void setID(String id) {
this.id = id;
}
public String getID() {
return id;
}
public void setLength(double length) {
this.length = length;
}
public double getLength() {
return length;
}
public abstract String getDetails();
}
The subclass Square as follow
public class Square extends Shape{
public Square() {
super();
}
public Square(String id , double side) {
super(id, side);
}
#Override
public String getDetails() {
return "Square => Id : "+getID() +", Side : "+ getLength() + ",Area : "+(getLength() * getLength());
}
}
The subclass Circle as follow
public class Circle extends Shape{
public Circle(){
super();
}
public Circle (String id, double radius) {
super(id, radius);
}
#Override
public String details() {
return "Circle => Id : "+getID() + ", Radius : "+ getLength() + ",Area: "+(3.14*(getLength() * getLength()));
}
}
The ShapeManager class as follow, this is not a completed class
public class ShapeManager {
public Shape createShape() {
}
public void updateLength(String id ){
}
public void deleteShape(String id) {
}
public void listShapes() {
}
}
ShapeManager have an association with Shape
ShapeManager --1------0..*--> Shape
The design of this package (All the classes above) can not be changed, implementation must be following OCP (Open-Closed Principle).
My question is: How am I suppose to complete createShape method? Without parameter, it is seemingly impossible to create an object either a Rectangle or Circle.
ShapeManager cannot create a shape if not knowing what this shape is (Square, Circle or something else). And it really doesn't know because you say the method createShare has no parameters. Either you misunderstood the question or the lecturer didn't explain it well. You should ask him/her for clarifications. If you look at the libraries of Java or any other OO language, I am pretty sure you won't find such scenario and implementation pattern as the one you gave in your example.
#croraf
You should find some other reading I think e.g. the classic book http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612. The main idea of a factory is that it returns something whose type the caller doesn't know, and doesn't care about. For example, if you have a method createSocket() in some SocketFactory, this method is usually defined to return an interface or an abstract class Socket. But actually it returns new SocketImpl1() and new SocketImpl2() which are concrete classes. What the factory returns may depend on many things - a system property, the underlying OS, anything you can think of. The main idea is that the factory centralizes the creation of Socket objects at one single place. This way, if you need to make a change, you can make it just in the factory. I think this book also has some decent Java counterparts too, you may look around. Other free good sources are referenced here.
Real world examples of Factory Method pattern
I think you should have something like this, similar to how BorderFactory from java API works.
public class ShapeManager {
public Shape createCircle() {
...
return Circle;
}
public Shape createSquare() {
....
return Square;
}
...
public void updateLength(String id ){
}
public void deleteShape(String id) {
}
public void listShapes() {
}
}
You can't create shape without knowing type which shape would You like to create. You can define enumeration for types and pass the type value to the createShape(). And there You can switch between types and create the concrette shape You want.
For me, Its classic Factory pattern.
public class ShapeFactory {
public abstract Shape getShape(int shapeId);
}
public interface Const {
public static final int SHAPE_CIRCLE =1;
public static final int SHAPE_SQUARE =2;
}
public class SimpleShapeFactory extends ShapeFactory throws BadShapeException {
public Shape getShape(int shapeTypeId){
Shape shape = null;
if(shapeTypeId == Const.SHAPE_CIRCLE) {
//in future can reuse or cache objects.
shape = new Circle();
}
else if(shapeTypeId == Const.SHAPE_SQUARE) {
//in future can reuse or cache objects
shape = new Square();
}
else throw new BadShapeException("ShapeTypeId="+ shapeTypeId);
return shape;
}
}
Calling:
ShapeFactory factory = new SimpleShapeFactory();
//returns a Shape but whether it is a Circle or a
//Square is not known to the caller.
Shape s = factory.getShape(1);
s.getDetails(); // circle details called
//returns a Shape but whether it is a Circle or a
//Square is not known to the caller.
s = factory.getShape(2);
s.getDetails(); //Square details called
References:
The Open Close Principle states that the design and writing of the code should be done in a way that new functionality should be added with minimum changes in the existing code. The design should be done in a way to allow the adding of new functionality as new classes, keeping as much as possible existing code unchanged.

Categories