One array containing different Object classes - java

So I've got an Object class Item and an Object class Trap. These two share variables called name and icon. I want to be able to put both of these classes into one array called special and be able to access the components of Item and Trap by using special. Here's my code that I need to work.
if (special[x][y] == null)
return 0;
System.out.print(special[x][y].icon); /* here's where the issue is */
return 1;
What should special be an array of? Should I use an interface? And if so, how? I've been reading everywhere but I don't know how to describe my problem.

Give this a try:
class Base
{
String name;
Icon icon;
}
class Item extends Base { }
class Trap extends Base { }
List<Base> special = new ArrayList<>();
alternatively, you can make Base an interface, and use the implements keyword instead of extends for Item and Trap.

One way that may work is to use a superclass (class, abstract class, interface all work). This is a bad name for the superclass, but I'm sure that you will get the idea:
public class Thing {
String icon; // Every class that extends Thing has an icon
String name; // Every class that extends Thing has a name
public Thing(String newIcon, String newName) {
icon = newIcon;
name = newName;
}
public String getIcon() {
return this.icon;
}
public String getName() {
return this.name;
}
}
public class Trap extends Thing {
public Trap() {
super("newIcon", "newName"); // Sets this Traps's name and icon values
}
}
public class Item extends Thing {
public Item() {
super("newIcon", "newName"); // Sets this Item's name and icon values
}
}
You can add whatever methods/variables that you want to Trap and Item, and, as long as they are legal in and of themselves, they will work.

Make an interface for Item and Trap which contains the methods they should share.
public interface GameObject {
String getName();
Image getIcon();
}
You can then create the Item and Trap classes by implementing this interface. For example
public class Trap implements GameObject {
private String name;
private Image icon;
public GameObject(String name, Image icon) {
this.name = name;
this.icon = icon;
} ...
By declaring this class implements GameObject it means we have to create the getName and getIcon methods. You do this by using an #Override annotation.
public class Trap implements GameObject {
private String name;
private Image icon;
public GameObject(String name, Image icon) {
this.name = name;
this.icon = icon;
}
#Override
public String getName() {
return name;
}
#Override
public Image getIcon() {
return icon;
}
}
Now that it implements GameObject we can add it to a list that holds GameObject types
List<GameObject> special = new ArrayList<>();
myList.add(new Trap(myTrapName, myTrapImage));
myList.add(new Item(myItemName, myItemImage));
We can then call the methods without worrying if that particular GameObject is an Item or a Trap
for (GameObject obj : special) {
System.out.println(obj.getName());
}

You should use an Interface
public interface SpecialInterface{
//you actually do not need any code, usually interfaces are called something+able
String getIcon();//this method will be filled in all the objects implementing this interface
}
So now you implement the interface in both your classes, for example:
public class Trap implements SpecialInterface{
//...
}
Now that you want to iterate your items and traps, you can do something like:
System.out.println(special[x][y].getIcon());
or..
if(special[x][y] instanceof Trap){
Trap oneTrap = (Trap) special[x][y]; //here you transform your SpecialInterface object in a Trap object
System.out.println(special[x][y].icon);
}else{
Item oneItem = (Item) special[x][y];
System.out.println(special[x][y].icon);
}
Note: Your Trap and Item objects should be declared like:
SpecialInterface trap = new Trap();
or
SpecialInterface item = new Item();
Otherwise you can't insert this objects in your matrix.

What should special be an array of? Should I use an interface? And if so, how?
If you want an array that can accommodate elements of two different types, then its element type must be a supertype of both. That could be an interface that both types implement, or a superclass of both.
I'd encourage you to access the members via accessor methods (e.g. getIcon()). If you insist on accessing them directly, as in your example, then the interface option is not possible, and the members you want to access must belong to the superclass (or one of its superclasses).
For example,
public interface GameObject {
String getName();
Icon getIcon();
}
public class Trap implements GameObject {
private final String name;
private final Icon icon;
public Trap(String name, Icon icon) {
this.name = name;
this.icon = icon;
}
#Override
public String getName() {
return name;
}
#Override
public Icon getIcon() {
return icon;
}
}
(... and similar for Item ...)
GameObject[][] special = /* ... */;
// ...
if (special[x][y] == null) {
return 0;
}
System.out.print(special[x][y].getName());
return 1;

public class Entity {
String name;
Icon icon;
}
public class Item extends Entity {
...
...
}
public class Trap extends Entity {
...
...
}
Entity[][] special = new Entity[5][10];
and now you can insert either of the two classes in special 2D array and you can use the exact same code that you've supplied in your question.
if (special[x][y] == null)
return 0;
System.out.print(special[x][y].icon); /* here's where the issue is */
return 1;

Related

Refactoring java classes where methods have different parameter types

I have two classes that extend an abstract class in a very similar manner, and I'd like to abstract out the common parts since I will likely have to use this again. They each return a ThingLink containing data linking them to a Parent object. They also return a Widget that varies based on the class, but only up to their name. Here is the pattern:
public abstract class SomeClass extends TopClass {
protected abstract Widget createWidget();
public void someMethod() { // Does something }
}
public class ThingA extends SomeClass {
private static final String INFO_TYPE = "int";
public ThingLink newLink(Parent master, Int info) {
ThingLink link = new ThingLink(parent, ThingA.class);
link.addData(INFO_TYPE, info);
return link;
}
public Widget createWidget() {
// Stuff to get someData
return ThingAWidget.createMe(someData);
}
}
public class ThingB extends SomeClass {
private static final String INFO_TYPE = "String";
public ThingLink newLink(Parent master, String info) {
ThingLink link = new ThingLink(parent, ThingB.class);
link.addData(INFO_TYPE, info);
return link;
}
public Widget createWidget() {
// Stuff to get someData
return ThingBWidget.createMe(someData);
}
}
I have no access to TopClass, the ThingLink class, or the Widget class. I was trying to abstract out the common parts using generics, but I can't seem to figure out if that will provide a complete solution. My big problem is figuring out how to get the pieces that are self-referential. I would like a class something like:
public abstract class Thing<T> extends SomeClass {
private String infoType;
public void setInfoType(String type) { infoType = type; }
public ThingLink newLink(Parent master, T info {
ThingLink link = new ThingLink(parent, ???????????);
link.addData(infoType, info);
return link;
}
public Widget createWidget() {
// Stuff to get someData
return ??????????????.createMe(someData);
}
}
Keep in mind that I am fairly new to Java, and self-taught, but I am trying very hard to make some bigger leaps and really understand how to write good code. I appreciate your help.

Make several classes have the same attributes without inheritance

I'm facing a problem in Java.
I need to have several classes with the same attributes ( for example a Position and a boolean isWalkable ).
But I don't want these classes to inherit from a class Element because that would prevent me from using inheritance later.
I thought of an interface (so that the interface has the attributes), but apparently you can't have an interface inherit from a class.
There must be a way because otherwise I would have to copy/paste my attributes and there methods.
Thanks in advance for anyone who has an idea on how to overcome this problem.
For this, I would consider composition over inheritance.
public class Main {
public static void main(String[] args) {
AgentWrapper agentWrapper = new AgentWrapper(new Agent1(), false, 1);
System.out.println("isWalkable: " + agentWrapper.isWalkable());
System.out.println("position: " + agentWrapper.getPosition());
agentWrapper.getAgent().doSomething();
}
}
interface Agent {
void doSomething();
}
class Agent1 implements Agent {
public void doSomething() {
System.out.println("Agent1");
}
}
class Agent2 implements Agent {
public void doSomething() {
System.out.println("Agent1");
}
}
class AgentWrapper {
private final Agent agent; //Wrapped instance.
private final boolean isWalkable;
private final int position;
public AgentWrapper(Agent agent, boolean isWalkable, int position) {
this.agent = agent;
this.isWalkable = isWalkable;
this.position = position;
}
public Agent getAgent() {
return agent;
}
public boolean isWalkable() {
return isWalkable;
}
I suspect you might need an interface anyway, if you want to treat your objects generically - e.g. loop over all of them and draw each one. E.g. assuming your elements include "cats" and "houses":
interface Element{
public point getPosition();
public boolean isWalkable();
}
class Cat implements Element{
private Point position;
private String catBreed; // example of cat-specific data
public point getPosition() {return position;}
public boolean isWalkable() {return true;} // cats can walk
...
}
class House implements Element{
private Point position;
private String streetAddress; // example of house-specific data
public point getPosition() {return position;}
public boolean isWalkable() {return false;} // houses cannot walk
..
}
// Finally, using that common interface:
Element[] allGameObjects= {new Cat(...), new Cat(...), new House(...) };
for(Element e:allGameObjects)
draw(e, e.getPosition());
That was good enough for several system I wrote... but as other replies correctly mentioned, you might refactor to use composition - however it might not be a 100% clear-cut. I mean, I can understand if you feel Cat or House should be managed independently from their position... but what about isWalkable?
// Position is easy to separate:
class Cat { String catBreed; ... }
class House{ String streetAddress; ... }
class ElementWrapper implements Element{
Point position;
Object theObject; // could hold Cat or House
public Point getPosition() {return position;}
// however, isWalkable is a bit tricky... see remark below
}
But 'isWalkable' is tricky because in classic polymorphism you'd expect House/Cat to tell you whether they can walk (meaning they should implement an interface anyway). If you absolutely don't want (or cant) have it, you may compromise on polymorphism and do something in the lines of instanceof (if theObject is instanceof Cat then it can walk, if it's instanceof House it cannot walk, etc).
You can extend an abstract base class(containing nothing) or You can use the Decorator pattern as somebody suggested in the comments, for more information related to Decorator pattern you can read this link.

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.

Use actual type of the class when using inheritance

Let's say we have a class with the following method:
public class Entry {
private String name;
public static Entry getOrCreate(String name) {
// ...
return new Entry(name);
}
}
This class may be subclassed (e.g. SubEntry), and the logic behind "getOrCreate" does not change. But the subclasses should not return a new object of the type Entry, but of the type of the respective subclass (e.g. return SubEntry(name))
How can I realize this without reimplementing the method getOrCreate for every subclass of Entry? Is there a term for this kind of technique?
Subclassing Entry does not affect the getOrCreate method because static methods are not part of a class instance; they do not logically belong in any class.
If you instead move getOrCreate into a non-static Factory class, you can use some Generics magic to determine the returned type:
public class Entry {
private String name;
}
abstract class AbstractEntryFactory<T extends Entry>
public abstract T getOrCreate(String name);
}
public class EntryFactory extends AbstractEntryFactory<Entry>
#Override
public Entry getOrCreate(String name) {
// ...
return new Entry(name);
}
}
public class SubEntryFactory extends AbstractEntryFactory<SubEntry>
#Override
public SubEntry getOrCreate(String name) {
// ...
return new SubEntry(name);
}
}
Actually calling the getOrCreate would look different from what it would look like with your code. Instead of this:
Entry myEntry = Entry.getOrCreate("my name");
It would instead look like this:
Entry myEntry = new EntryFactory().getOrCreate("my name");
Or this:
SubEntry myEntry = new SubEntryFactory().getOrCreate("my name");
Assuming you wanted to be able to call Entry.getOrCreate() to create a type of SubEntry, you'll have to pass along some extra information. The reason is that the getOrCreate() method is not inherited by SubEntry, since it is a static method. So if you want to call it the way I mentioned, you'll have to pass along the class name that you want to create. In the code below there are no checks to validate that Class clazz is an Entry or a subtype, but this gives you a start.
import java.lang.reflect.Constructor;
public class TestClass {
public static void main(String[] args) {
Entry entry = (Entry)Entry.getOrCreate("entry", Entry.class);
SubEntry subEntry = (SubEntry)SubEntry.getOrCreate("subEntry", SubEntry.class);
System.out.println("entry class: " + entry.getClass().getName());
System.out.println("subEntry class: " + subEntry.getClass().getName());
}
}
class Entry {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static Object getOrCreate(String name, Class clazz) {
// If a constructor is created that takes a String, such as "public Entry(String name)",
// then each sub class will need to implement that method. Instead I used a getter and
// setter for the name attribute.
try {
Entry entry = (Entry)clazz.newInstance();
entry.setName(name);
return entry;
}
catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
class SubEntry extends Entry {
}
The end result is this output:
entry class: Entry
subEntry class: SubEntry
There are two questions you are asking:
How do I do this?
What is this technique called?
The second one is much more important than the first.
It seems to me like what you are trying to achieve is similar to the concept of cloning (link) or virtual constructor. But you would like this to be a static method, which raises the question as to why? Since a static method is tied to a certain class, not an instance, you should call it through that class in which case you may just as well explicitly be calling new. But having searched for "retrive class in static context" I would say it is not possible to do exactly what you wrote in the question.
If you convert the static method to a normal method, this can be done by using reflection:
class Entry {
private String name;
public Entry(String name) {
this.name = name;
}
public Entry() {
this.name = null;
}
public Entry getOrCreate(String name) {
try {
return getClass().getConstructor(String.class).newInstance(name);
} catch (Exception e) {
return new Entry(name);
}
}
}
class BetterEntry extends Entry {
public BetterEntry(String name) {
super(name);
}
public BetterEntry() {
super();
}
}
You would then be calling the function from an instance, like so:
Entry a = new Entry().getOrCreate("First");
Entry b = new BetterEntry().getOrCreate("Second");
Entry c = b.getOrCreate("Third");
The dynamic types of a, b, c are Entry, BetterEntry and BetterEntry. You could leave out the default constructors, but I added them to make calling getOrCreate feel more like a static method.
If you really want the method to be static, the simplest way would be to just reimplement this function in every subclass.

Extending class with hidden constructors

I have a base class FiniteStateMachine which has a list of State. The states can only be instantiated through the FSM, so I can make sure the list is updated.
public class FiniteStateMachine {
private List<State> states = new ArrayList<State>();
public State addState(String name) {
State s = new State(name);
states.add(s);
return s;
}
protected void addState(State s) {
states.add(State s);
}
public static class State {
private String name;
protected State(String name) { this.name = name; }
}
}
Now, I want to extend both the FiniteStateMachine and State classes into MyFSM and MyState classes. I still want to make sure the new MyState states can only be created through the FSM, to ensure they are part of the list.
This is what I have done so far:
public MyState extends FinitStateMachine.State {
private int n;
protected MyState(int n, String name) {
super(name);
this.n = n;
}
}
public MyFSM extends FiniteStateMachine {
#Override
public State addState(String name) {
throw new UnsupportedOperationException();
}
public MyState addState(int n, String name) {
MyState s = new MyState(n, name);
super.addState(s);
return s;
}
}
I am not sure I am doing it right.
First, the original State class is an inner class of FiniteStateMachine, and here I am extending it outside my new class MyFSM.
Second, I had to add a new method to the original FiniteStatMachine
protected void addState(State s) {
states.add(State s);
}
otherwise I don't know how could I have attached a state of my new MyState class to the FiniteStateMachine list.
Third, instead of overriding the addState(name) method I kind of crippled it and throw an exception and instead put a whole new method to return the new class.
If there is a coding pattern for these situations I am not aware of it. But I'd like to know, so I don't go reinventing the wheel.
If you make the list variable protected, you may access it from child classes too, without the add method. It depends on what you want to do later, and how visible you want the list to be. If you want to be able to add states from outside of the inheritance hierarchy, or if you don't want the list to be visible within the whole package,you may need the addState method though.

Categories