The example is as follows: I have a Box
that needs to be filled with some Thing
s. I'm interested only in weight of each thing. Also, beside weight, I need to correctly identify the thing that I'm measuring. Each thing type has different Id type. In this case I have toys and fruits, which have ToyId
and FruitId
respectively. In the end, I need to be able to print thing identifier and thing weight.
Question: Is it somehow possible to access specific methods on ThingId
s without using instanceof operator (as in example)?
class Color{}
interface ThingId {}
class FruitId implements ThingId {
String name; //"apple", "orange", ...
FruitId(String name){ this.name = name; }
String getName(){ return this.name; }
}
class ToyId implements ThingId {
String shape; //"square", "circle", ...
Color color; //"red", "blue"...
ToyId(String shape, Color color){ this.shape = shape; this.color = color; }
String getShape(){ return this.shape; }
Color getColor(){ return this.color; }
}
class Thing{
ThingId thingId;
Integer weight;
public Thing(ThingId thingId, Integer weight){
this.thingId = thingId;
this.weight = weight;
}
ThingId getThingId(){ return this.thingId; }
Integer getWeight(){ return this.weight; }
}
class Box {
Set<Thing> things = new HashSet<>();
void addThing(Thing thing){
this.things.add(thing);
}
Collection<Thing> getThings(){
return this.things;
}
}
class Program {
public static void main(String[] args) {
FruitId appleId = new FruitId("apple");
Thing apple = new Thing(appleId, 1);
ToyId cubeId = new ToyId("square", new Color());
Thing cube = new Thing(cubeId, 22);
Box box = new Box();
box.addThing(apple);
box.addThing(cube);
for(Thing t : box.getThings()){
System.out.print("Thing Id is: ");
if(t.getThingId() instanceof FruitId) { //any other possibility than using instance of?
process((FruitId)t.getThingId());
}
if(t.getThingId() instanceof ToyId){ //any other possibility than using instance of?
process((ToyId)t.getThingId());
}
System.out.println("Weight is : " + t.getWeight());
}
}
static void process(FruitId fruitId){
System.out.println(fruitId.getName());
}
static void process(ToyId toyId){
System.out.println(toyId.getShape() + toyId.getColor());
}
}
UPDATE
OK, I think Visitor pattern could be useful here:
class Color{}
interface ThingId {
void visitThingId(ThingIdVisitor visitor);
}
class FruitId implements ThingId {
String name; //"apple", "orange", ...
FruitId(String name){ this.name = name; }
String getName(){ return this.name; }
@Override
public void visitThingId(ThingIdVisitor visitor) {
visitor.process(this);
}
}
class ToyId implements ThingId {
String shape; //"square", "circle", ...
Color color; //"red", "blue"...
ToyId(String shape, Color color){ this.shape = shape; this.color = color; }
String getShape(){ return this.shape; }
Color getColor(){ return this.color; }
@Override
public void visitThingId(ThingIdVisitor visitor) {
visitor.process(this);
}
}
class Thing{
ThingId thingId;
Integer weight;
public Thing(ThingId thingId, Integer weight){
this.thingId = thingId;
this.weight = weight;
}
ThingId getThingId(){ return this.thingId; }
Integer getWeight(){ return this.weight; }
}
class Box {
Set<Thing> things = new HashSet<>();
void addThing(Thing thing){
this.things.add(thing);
}
Collection<Thing> getThings(){
return this.things;
}
}
class ThingIdVisitor{
void process(FruitId fruitId){
System.out.println(fruitId.getName());
}
void process(ToyId toyId){
System.out.println(toyId.getShape() + toyId.getColor());
}
}
class Program {
public static void main(String[] args) {
FruitId appleId = new FruitId("apple");
Thing apple = new Thing(appleId, 1);
ToyId cubeId = new ToyId("square", new Color());
Thing cube = new Thing(cubeId, 22);
Box box = new Box();
box.addThing(apple);
box.addThing(cube);
for(Thing t : box.getThings()){
System.out.print("Thing Id is: ");
t.getThingId().visitThingId(new ThingIdVisitor());
System.out.println("Weight is : " + t.getWeight());
}
}
}
I don't really get what you're trying to achieve. First of all, I don't get the use of the interface ThingId
. Second, I think you're a bit confused about interfaces and inheritance. If I were you, I'd look up polymorphism .
Anyway, I propose you remove the ThingId
interface and let the FruitId
and ToyId
classes extend the Thing
class. As your collection only exists of Thing
s, and as your Fruit
and Toy
classes all extend this Thing
class and thus implement the getWeight()
method, you should not use instanceof
anymore.
But please, read up on polymorphism .
your interface ThingId
must provide the respective methods that you want to have.
If you simple want to print out information, then you can use like a simple
public String getInformation();
Then the implementations can return the information that is relevant for them and you can simply work with ThingId
in your application code.
BTW: As you are storing your Thing
s in a HashSet
make sure to implement equals
and hashCode
in all Thing
implementations
Also I dont really see, why you need a Thing
and a ThingId
, as ThingId
seems a bit more than a simple id and actually a thing. So for me it seems that ThingId
is redundant and all can be achieved by the having different Thing
s
Since you are calling the same method process
on both the instance types, why not add that method to ThingId
interface itself.
By doing so, you could just call:
t.getThingId().process();
Instead of finding the instance type and calling respective methods.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.