Is it still a code smell if a class knows all subtypes but not using instanceof and downcasting?
According to Instanceof code smell, I know using "instanceof" is a code smell, so suppose there is a game with some Tools: Tool.java: public interface Tool{ public void printInfo(); } Sword.java: public class Sword implements Tool{ public int atk=10; public void printInfo(){ System.out.println("Sword : atk="+this.atk); } } Shield.java: public class Shield implements Tool{ public int def=20; public void printInfo(){ System.out.println("Shield: def="+this.def); } } MagicCloth.java: public class MagicCloth implements Tool{ public int atk=5; public int def=20; public int speed=15; public void printInfo(){ System.out.println("MagicCloth: atk="+this.atk+" ,def="+this.def+" ,speed="+this.speed); } } And when a Player that equips the tools, there is a function "printToolsAndTotalStats()" to list each tool and also show the total values of all stats: Player.java (with instanceof and downcasting) import java.util.ArrayList; public class Player{ private ArrayList tools=new ArrayList(); public void printToolsAndTotalStats(){ int totalAtk=0; int totalDef=0; int totalSpeed=0; for(Tool tool : tools){ tool.printInfo(); if(tool instanceof Sword){ Sword sword=(Sword)tool; totalAtk+=sword.atk; }else if(tool instanceof Shield){ Shield shield=(Shield)tool; totalDef+=shield.def; }else if(tool instanceof MagicCloth){ MagicCloth magicCloth=(MagicCloth)tool; totalAtk+=magicCloth.atk; totalDef+=magicCloth.def; totalSpeed+=magicCloth.speed; } } System.out.println("total atk:"+totalAtk+" , total def:"+totalDef+" , totalSpeed:"+totalSpeed); } public static void main(String[] args){ Player player=new Player(); Tool t1=new MagicCloth(); player.tools.add(t1); Tool t2=new Shield(); player.tools.add(t2); Tool t3=new MagicCloth(); player.tools.add(t3); Tool t4=new Sword(); player.tools.add(t4); player.printToolsAndTotalStats(); } } Which I know Player above is bad because it is using "instanceof" and downcasting to do the job. However, what if Player still knows all the subtypes, but not using "instanceof" and downcasting? For example: Player.java (without instanceof and downcasting) import java.util.ArrayList; public class Player{ private ArrayList tools=new ArrayList(); private ArrayList magicCloths=new ArrayList(); private ArrayList shields=new ArrayList(); private ArrayList swords=new ArrayList(); public void printToolsAndTotalStats(){ int totalAtk=0; int totalDef=0; int totalSpeed=0; for(Tool tool : tools){ tool.printInfo(); for(Sword sword : swords){ if(System.identityHashCode(sword)==System.identityHashCode(tool)){ totalAtk+=sword.atk; break; } } for(Shield shield : shields){ if(System.identityHashCode(shield)==System.identityHashCode(tool)){ totalDef+=shield.def; break; } } for(MagicCloth magicCloth : magicCloths){ if(System.identityHashCode(magicCloth)==System.identityHashCode(tool)){ totalAtk+=magicCloth.atk; totalDef+=magicCloth.def; totalSpeed+=magicCloth.speed; break; } } } System.out.println("total atk:"+totalAtk+" , total def:"+totalDef+" , totalSpeed:"+totalSpeed); } public static void main(String[] args){ Player player=new Player(); MagicCloth t1=new MagicCloth(); player.magicCloths.add(t1); player.tools.add(t1); Shield t2=new Shield(); player.shields.add(t2); player.tools.add(t2); MagicCloth t3=new MagicCloth(); player.magicCloths.add(t3); player.tools.add(t3); Sword t4=new Sword(); player.swords.add(t4); player.tools.add(t4); player.printToolsAndTotalStats(); } } Which besides Tool, Player now also stores the reference of each subtype individually: private ArrayList magicCloths=new ArrayList(); private ArrayList shields=new ArrayList(); private ArrayList swords=new ArrayList(); . . . MagicCloth t1=new MagicCloth(); player.magicCloths.add(t1); player.tools.add(t1); Shield t2=new Shield(); player.shields.add(t2); player.tools.add(t2); MagicCloth t3=new MagicCloth(); player.magicCloths.add(t3); player.tools.add(t3); Sword t4=new Sword(); player.swords.add(t4); player.tools.add(t4); and use Syste

According to Instanceof code smell, I know using "instanceof" is a code smell, so suppose there is a game with some Tools:
Tool.java:
public interface Tool{
public void printInfo();
}
Sword.java:
public class Sword implements Tool{
public int atk=10;
public void printInfo(){
System.out.println("Sword : atk="+this.atk);
}
}
Shield.java:
public class Shield implements Tool{
public int def=20;
public void printInfo(){
System.out.println("Shield: def="+this.def);
}
}
MagicCloth.java:
public class MagicCloth implements Tool{
public int atk=5;
public int def=20;
public int speed=15;
public void printInfo(){
System.out.println("MagicCloth: atk="+this.atk+" ,def="+this.def+" ,speed="+this.speed);
}
}
And when a Player that equips the tools, there is a function "printToolsAndTotalStats()" to list each tool and also show the total values of all stats:
Player.java (with instanceof and downcasting)
import java.util.ArrayList;
public class Player{
private ArrayList tools=new ArrayList();
public void printToolsAndTotalStats(){
int totalAtk=0;
int totalDef=0;
int totalSpeed=0;
for(Tool tool : tools){
tool.printInfo();
if(tool instanceof Sword){
Sword sword=(Sword)tool;
totalAtk+=sword.atk;
}else if(tool instanceof Shield){
Shield shield=(Shield)tool;
totalDef+=shield.def;
}else if(tool instanceof MagicCloth){
MagicCloth magicCloth=(MagicCloth)tool;
totalAtk+=magicCloth.atk;
totalDef+=magicCloth.def;
totalSpeed+=magicCloth.speed;
}
}
System.out.println("total atk:"+totalAtk+" , total def:"+totalDef+" , totalSpeed:"+totalSpeed);
}
public static void main(String[] args){
Player player=new Player();
Tool t1=new MagicCloth();
player.tools.add(t1);
Tool t2=new Shield();
player.tools.add(t2);
Tool t3=new MagicCloth();
player.tools.add(t3);
Tool t4=new Sword();
player.tools.add(t4);
player.printToolsAndTotalStats();
}
}
Which I know Player above is bad because it is using "instanceof" and downcasting to do the job. However, what if Player still knows all the subtypes, but not using "instanceof" and downcasting? For example:
Player.java (without instanceof and downcasting)
import java.util.ArrayList;
public class Player{
private ArrayList tools=new ArrayList();
private ArrayList magicCloths=new ArrayList();
private ArrayList shields=new ArrayList();
private ArrayList swords=new ArrayList();
public void printToolsAndTotalStats(){
int totalAtk=0;
int totalDef=0;
int totalSpeed=0;
for(Tool tool : tools){
tool.printInfo();
for(Sword sword : swords){
if(System.identityHashCode(sword)==System.identityHashCode(tool)){
totalAtk+=sword.atk;
break;
}
}
for(Shield shield : shields){
if(System.identityHashCode(shield)==System.identityHashCode(tool)){
totalDef+=shield.def;
break;
}
}
for(MagicCloth magicCloth : magicCloths){
if(System.identityHashCode(magicCloth)==System.identityHashCode(tool)){
totalAtk+=magicCloth.atk;
totalDef+=magicCloth.def;
totalSpeed+=magicCloth.speed;
break;
}
}
}
System.out.println("total atk:"+totalAtk+" , total def:"+totalDef+" , totalSpeed:"+totalSpeed);
}
public static void main(String[] args){
Player player=new Player();
MagicCloth t1=new MagicCloth();
player.magicCloths.add(t1);
player.tools.add(t1);
Shield t2=new Shield();
player.shields.add(t2);
player.tools.add(t2);
MagicCloth t3=new MagicCloth();
player.magicCloths.add(t3);
player.tools.add(t3);
Sword t4=new Sword();
player.swords.add(t4);
player.tools.add(t4);
player.printToolsAndTotalStats();
}
}
Which besides Tool, Player now also stores the reference of each subtype individually:
private ArrayList magicCloths=new ArrayList();
private ArrayList shields=new ArrayList();
private ArrayList swords=new ArrayList();
.
.
.
MagicCloth t1=new MagicCloth();
player.magicCloths.add(t1);
player.tools.add(t1);
Shield t2=new Shield();
player.shields.add(t2);
player.tools.add(t2);
MagicCloth t3=new MagicCloth();
player.magicCloths.add(t3);
player.tools.add(t3);
Sword t4=new Sword();
player.swords.add(t4);
player.tools.add(t4);
and use
System.identityHashCode(???)==System.identityHashCode(tool)
to find the suitable subtype, is it still considered as code smell and "non OOP"?