I have a Composition object that contains 4 ArrayList objects, each of which contains objects of a particular subclass of my Abstract class "Role". The 4 subclasses are Bruiser, Healer, Tank, Damage Dealer. The values of the Composition object's properties are incremented accordingly each time a Role subclass gets added to one of its ArrayLists, like so (note: "this" corresponds to the Composition object) : private void addMutualContribution(Role r) { this.mobility += r.getMobility(); this.defensiveRating += r.getPeeling(); this.waveclear += r.getWaveclear(); this.burstMitigation += r.getBurstMitigaion(); this.sustainedMitigation += r.getSustainedMitigation(); } public void addBruiserContribution(Bruiser b) { addMutualContribution(b); this.offensiveRating += b.getPressure(); this.damage += b.getDamage(); this.frontlineRating += b.getFrontlineRating(); } public void addDDContribution(DamageDealer d) { addMutualContribution(d); this.burstDamageRating += d.getBurstDamageRating(); this.sustainedDamageRating += d.getSustainedDamageRating(); this.damage += d.getDamageOutput(); this.offensiveRating += d.getAggression(); } public void addTankContribution(Tank t) { addMutualContribution(t); this.defensiveRating += t.getAntiMeleeEffectiveness(); this.offensiveRating += t.getEngage(); this.frontlineRating += t.getFrontlineRating(); } public void addHealerContribution(Healer h) { addMutualContribution(h); this.burstMitigation += h.getBurstHealing(); this.sustainedMitigation += h.getSustainedHealing(); if (h.hasLockdownProtection()) { this.lockdownProtection = true; } } To me, this implementation feels backwards. Ultimately I should only have the one public method to add a Role subclass to the composition, then the Composition should privately adjust its own properties based on which particular subclass is being added, something like this: public void addRole(CustomEnum roleType, Role r) { // increment properties inherent to all roles like mobility, waveclear, etc. // ... switch (roleType) { case BRUISER: addBruiserContribution(r); break; case TANK: addTankContribution(r); break; case DAMAGE_DEALER: addDDContribution(r); break; case HEALER: addHealerContribution(r); break; default: throw new InvalidArgumentException("Wrong roletype provided!"); } } This doesn't work without me having to hardcast the Role abstract class into a particular subclass before passing it to the appropriate "add__Contribution()" method, which is a big red-flag. Thus it feels like I missed an opportunity for cleaner polymorphism, but I can't figure out where. How could I make my code well-formed and polymorphic to suit my needs? Edit: Including more of my code to further flesh out my problem! Role Abstract class: public abstract class Role { protected String name; protected int mobility; protected int waveclear; protected int peeling; protected int burstMitigation; protected int sustainedMitigation; protected boolean lockdown; protected boolean aaControl; protected AttackRange range; public String getName() { return name; } public int getMobility() { return mobility; } public int getWaveclear() { return waveclear; } public int getPeeling() { return peeling; } public int getBurstMitigaion() { return burstMitigation; } public int getSustainedMitigation() { return sustainedMitigation; } public boolean hasLockdown() { return lockdown; } public boolean hasAAControl() { return aaControl; } public AttackRange getRange() { return range; } } Bruiser Subclass: public class Bruiser extends Role { private int pressure; private int damage; private int frontlineRating; protected Bruiser() { } public int getPressure() { return pressure; } public int getDamage() { return damage; } public int getFrontlineRating() { return frontlineRating; } } Healer subclass: public class Healer extends Role { private int burstHealing; private int sustainedHealing; private boolean lockdownProtection; protected Healer() { } public int getBurstHealing() { return burstHealing; } public int getSustainedHealing() { return sustainedHealing; } public boolean hasLockdownProtection() { return lockdownProtection; } } Tank subclass: public class Tank extends Role { private int antiMeleeEffectiveness; private int frontlineRating; private int engage; protected Tank() { } public int getAntiMeleeEffectiveness() { return antiMeleeEffectiveness; } public int getFrontlineRating() { return frontlineRating; } public int getEngage() { return engage; } } Damage Dealer subclass: public class DamageDealer extends Role { private int burstDamageRating; private int sustainedDamageRating; private int aggression; private int damageOutput; protected DamageDealer() { } public int getBurstDamageRating() { return burstDamageRating; } public int getSustainedDamageRating() { return sustainedDamageRating; } public int getAggression() { return aggression; } public int getDamageOutput() { return damageOutput; } }