This isn't a matter of me being stuck, but rather I'm looking for a tidy way to write my code.
Essentially, I'm writing an event driven application. The user triggers an event, the event gets sent to the appropriate objects, and the objects handle the events. Now I'm working on writing the even handler methods, and I was hoping to use switch statements to determine how to handle the event. Right now whilst I'm working on the general structure, the event class is really simple:
public class Event {
public static enum Action {
MOVE, FOO, BAR
}
private Action action;
private int duration;
public Event(Action action, int duration) {
this.action = action;
this.duration = duration;
}
public Action getAction() {
return action;
}
public int getDuration() {
return duration;
}
Then, in another class, I'll have something like:
public void handleEvent(Event evt) {
switch(Event.getAction()) {
case MOVE: doSomething(); break;
case FOO: doSomething(); break;
case BAR: doSomething(); break;
default: break;
}
}
What I would like to do is something like this (though I would of course stick the switch statements into their own functions to avoid it turning into a nasty hairball of switches and cases):
public void handleEvent(Event evt) {
switch(Event.getAction()) {
case MOVE: switch(Event.getAction()) {
case UP: break;
case DOWN: break;
case LEFT: break;
case RIGHT: break;
}
case FOO: break;
case BAR: break;
default: break;
}
}
So, I'd want to create nested enums... like so:
public static enum Action {
public enum MOVE {UP, DOWN, LEFT, RIGHT}, FOO, BAR
}
It's not like I can't avoid the scenario, it would just be... convenient. So whilst the above doesn't actually work, is there some similar method to achieve this? It would be nice if I could send an event with the action "MOVE.UP", and the method would identify it first as an action of type MOVE, and then further identify that it is specifically in the UP direction. That's just a simple example, it would be grat if I could also make longer chains, something like "DELETE.PAGE1.PARAGRAPH2.SENTENCE2.WORD11.LETTER3". The way I see it, I'm just going to have to use Strings and lots of if/else statements. Hoping there's a better way! (Oh, and performance matters in my case, if that helps)
I believe that in Java, you can simply nest enums, as long as your non-enum constants come first.
enum Action
{
FOO,
BAR;
enum MOVE
{
UP,
DOWN,
LEFT,
RIGHT
}
}
This compiles for me and gives me the behavior you were looking for.
Perhaps use an inheritance hierarchy for the Events?
So you have:
- abstract Event
-- MoveEvent(Direction)
-- FooEvent()
-- BarEvent()
It may make more sense to have:
- abstract Event
-- abstract MoveEvent
--- MoveUpEvent
--- MoveDownEvent
--- MoveRightEvent
--- MoveLeftEvent
-- FooEvent
-- BarEvent
If all the Move events have a distance, then pass that into the MoveEvent constructor (which will ripple down).
you can nest them in an arbitrary order like this:
package nested;
import java.util.*;
import nested.Citrus.Orange;
interface HasChildren {
Set<Enum<?>> children();
}
enum Citrus implements HasChildren {
lemon, lime, orange;
Set<Enum<?>> children;
enum Orange implements HasChildren {
navel, valencia, blood;
Set<Enum<?>> children;
enum Navel implements HasChildren {
washinton, lateLane, caraCaraPink;
public Set<Enum<?>> children() {
return null;
}
}
static {
navel.children = new LinkedHashSet<Enum<?>>();
navel.children.addAll(EnumSet.allOf(Navel.class));
}
enum Blood implements HasChildren {
moro, taroco;
public Set<Enum<?>> children() {
return null;
}
}
static {
blood.children = new LinkedHashSet<Enum<?>>();
blood.children.addAll(EnumSet.allOf(Blood.class));
}
public Set<Enum<?>> children() {
return children != null ? Collections.unmodifiableSet(children) : null;
}
}
static {
orange.children = new LinkedHashSet<Enum<?>>();
orange.children.addAll(EnumSet.allOf(Orange.class));
}
public Set<Enum<?>> children() {
return children != null ? Collections.unmodifiableSet(children) : null;
}
}
public class EnumTreeNested {
static void visit(Class<?> clazz) {
Object[] enumConstants = clazz.getEnumConstants();
if (enumConstants[0] instanceof HasChildren)
for (Object o : enumConstants)
visit((HasChildren) o, clazz.getName());
}
static void visit(HasChildren hasChildren, String prefix) {
if (hasChildren instanceof Enum) {
System.out.println(prefix + ' ' + hasChildren);
if (hasChildren.children() != null)
for (Object o : hasChildren.children())
visit((HasChildren) o, prefix + ' ' + hasChildren);
} else
System.out.println("other " + hasChildren.getClass());
}
static <E extends Enum<E> & HasChildren> Set<E> foo() {
return null;
}
public static void main(String[] args) {
System.out.println(Citrus.Orange.Navel.washinton);
visit(Citrus.lemon, "");
System.out.println("----------------------");
visit(Citrus.orange, "");
System.out.println("----------------------");
visit(Citrus.class);
System.out.println("----------------------");
}
}
Related
I want to create a finite state machine and most of the example code I can find uses enums and I was just wondering if it gives an advantage over just using a string or int to store the state.
With Enum:
class TrafficLight {
enum State {
RED, YELLOW, GREEN
};
State state = State.GREEN;
public void iterate() throws InterruptedException {
switch (this.state) {
case RED:
System.out.println("RED");
Thread.sleep(1000);
this.state = State.GREEN;
break;
case GREEN:
System.out.println("GREEN");
Thread.sleep(1000);
this.state = State.YELLOW;
break;
case YELLOW:
System.out.println("YELLOW");
Thread.sleep(1000);
this.state = State.RED;
break;
}
}
public class Main {
public static void main(final String[] args) throws InterruptedException {
final TrafficLight a = new TrafficLight();
while (true) {
a.iterate();
}
}
}
With String
public class TrafficLight {
String state = "GREEN";
public void iterate() throws InterruptedException {
switch (state) {
case "RED":
System.out.println("RED");
Thread.sleep(1000);
state = "GREEN";
break;
case "GREEN":
System.out.println("GREEN");
Thread.sleep(1000);
state = "YELLOW";
break;
case "YELLOW":
System.out.println("YELLOW");
Thread.sleep(1000);
state = "RED";
break;
}
}
}
(Both use the same main method)
They both seem to be exactly the same to me I am just wondering if there are any cases in which enums are better or a string wouldn't work.
Thanks.
Main advantage for Enum over String : this is more specifically typed as Enum specifies possible values.
This makes your code both more robust and also better documented.
For a FSM and more generally bounded values, it is what you are looking for.
But for problems/domains where possible values are defined at runtime and not at compile time (retrieving from a database or whatever), Enum is not the best candidate.
Example of Enum interest in your case
With Enum, it will not compile as REDD is not declared in the State enum class:
case REDD:
System.out.println("RED");
Thread.sleep(1000);
this.state = State.GREEN;
break;
But with String, it will compile and just not work as expected :
case "REDD":
System.out.println("RED");
Thread.sleep(1000);
state = "GREEN";
break;
Enumerated values are instances of the enum class with own values for instance fields but also overriding abilities for instance methods
This is another advantage of enum in the FSM or any domain where the enumerated values are associated to specific properties/processings and where according to enumerated value, the fields values or the method behavior could differ.
For example, here we specify the behavior to get the next transition :
enum State {
YELLOW(){
#Override
public State next() {
return RED;
}
},
RED(){
#Override
public State next() {
return GREEN;
}
},
GREEN(){
#Override
public State next() {
return YELLOW;
}
};
public abstract State next();
}
Now, the enum holds enough logic to make the switch statement not needed any longer :
public void iterate() throws InterruptedException {
System.out.println(state);
Thread.sleep(1000);
state = state.next();
}
I've run into a problem in which my class contains several methods with a lot of duplicated code. The reason behind this is that each method traverses a list of entries and calls specific entry method.
In code...
The LowLevelClass class has the following structure:
public class LowLevelClass {
// constructor omitted
public boolean doSomethingA() {
// some non-duplicated code
return true;
}
public boolean doSomethingB() {
// some non-duplicated code
return true;
}
public boolean doSomethingC() {
// some non-duplicated code
return true;
}
}
The top level class contains a List of LowLevelClasses and has the same number of methods, but this time, with a lot of duplications:
public class HighLevelClass {
private List<LowLevelClass> classes = new ArrayList<>();
public HighLevelClass() {
this.classes.add(new LowLevelClass(/* params */));
this.classes.add(new LowLevelClass(/* params */));
this.classes.add(new LowLevelClass(/* params */));
}
public void doA() {
System.out.println("Doing ...");
for (LowLevelClass entry : classes) {
System.out.println("Doing something...");
entry.doSomethingA();
System.out.println("Done");
}
}
public void doB() {
System.out.println("Doing ...");
for (LowLevelClass entry : classes) {
System.out.println("Doing something...");
entry.doSomethingB();
System.out.println("Done");
}
}
public void doC() {
System.out.println("Doing ...");
for (LowLevelClass entry : classes) {
System.out.println("Doing something...");
entry.doSomethingC();
System.out.println("Done");
}
}
}
My goal is to have something in form of:
public class HighLevelClass {
private List<LowLevelClass> classes = new ArrayList<>();
public HighLevelClass() {
this.classes.add(new LowLevelClass());
this.classes.add(new LowLevelClass());
this.classes.add(new LowLevelClass());
}
public void doSomething(Lambda /* Functional interface*/ operation) {
System.out.println("Doing A");
for (LowLevelClass entry : classes) {
System.out.println("Doing something...");
entry.operation; // or something else...
System.out.println("Done");
}
}
public void doSomethingA() {
// my goal... and maybe in totally wrong direction is to send something in form of...
return doSomething(LowLevelClass::doSomethingA);
}
// etc
}
Can this be done in Java 8 with Lambdas? In other words, can I define the method to perform on each entry of the given list?
EDIT 1
The answers provided by Jorn Vernee and Joffrey are correct!
Ultimately, the solution was to use Predicate. (see EDIT 2 why I didn't use Consumer in the end...)
public class HighLevelClass {
private List<LowLevelClass> classes = new ArrayList<>();
public HighLevelClass() {
this.classes.add(new LowLevelClass());
this.classes.add(new LowLevelClass());
this.classes.add(new LowLevelClass());
}
public boolean doSomething(Predicate<LowLevelClass> function) {
System.out.println("Doing A");
for (LowLevelClass entry : classes) {
System.out.println("Doing something...");
boolean val = function.test(entry);
System.out.println("Done " + val);
}
return someEndVerdict;
}
public boolean doSomethingA() {
return doSomething(LowLevelClass::doSomethingA);
}
// etc
}
EDIT 2
My initial methods in HighLevelClass didn't contain boolean return type. That's the reason why I used Predicate (Predicate, as a contast to Consumer, returns boolean value which suited me better - and which I forgot to initially mention :((( )
Thanks for help and time!
You should not confuse the way you call a method, which may or may not involve a lambda, and the way you write a method, which involves finding the right argument types.
When you write a method, you need to focus on your arguments' types. If one of them is an object representing a function, what you need is to understand the appropriate signature that this function should match, and this will give you the functional interface you should put as type of your param.
In your case, you expect a function that takes 1 argument of type LowLevelClass and returns no value. You might be surprised by that, but you need to think of instance methods as functions that take an instance of the class (this) as an extra first argument (as opposed to static methods).
Therefore, the Consumer<LowLevelClass> interface is what you want:
public void doSomething(Consumer<LowLevelClass> operation) {
System.out.println("Doing A");
for (LowLevelClass entry : classes) {
System.out.println("Doing something...");
operation.accept(entry); // or something else...
System.out.println("Done");
}
}
public void doSomethingA() {
return doSomething(LowLevelClass::doSomethingA);
}
I'm kinda new to Java, and I'm trying to write an RPG of sorts.
Now, in the game the player character would have skills. These could be very diverse, from hurting enemies to healing the player and a lot of other things. It'd make sense to create a Skill class with an abstract applyEffect() method, to be defined on each particular skill.
However, I cannot have a non-abstract class containing abstract methods, and every skill should be an object of the Skill class, so it can't be abstract. The obvious solution is to make the Skill class abstract and create a subclass for every single skill, and then instantiate that into an object to use.
This approach seems a bit redundant. Is there anything else I could conceivably do in this situation?
EDIT: While we're at it, if I want an object that will appear a single time with standard variables, is there any workaround to making a class just for that one object and then instantiating it?
I would not write skills (like 'heal' and 'hide') as classes. I view classes as objects (players), and methods as abilities (skills). Skills like 'heal' or 'hide' are clearly better as methods than classes.
I would simply have one class that has all methods, but only the selected ones are available for use. Having the skills as enums isn't a bad idea either.
enum Skill {
HEAL, HIDE, ATTACK, THROW
}
class Player {
boolean canHeal = false;
boolean canHide = false;
boolean canAttack = false;
boolean canThrow = false;
Player(Skill[] skills) {
for(skill : skills) {
switch(skill) {
case Skills.HEAL: canHeal = true;
break;
case Skills.HIDE: canHide = true;
break;
case Skills.ATTACK: canAttack = true;
break;
case Skills.THROW: canThrow = true;
break;
default: //error
}
}
}
void heal() {
[...]
}
void hide() {
[...]
}
void attack() {
[...]
}
void throw() {
[...]
}
boolean canHeal() {
return canHeal;
}
boolean canHide() {
return canHide;
}
boolean canAttack() {
return canAttack;
}
boolean canThrow() {
return canThrow;
}
}
Now the players can be restricted to only use the methods that should be available to them. What I would do is probably to write a GameHandler-class to take care of everything and do all the checking there.
How about this:
public abstract class Skill {
public abstract void applyEffect();
}
... somewhere else ...
Skill dig = new Skill() {
#Override
public void applyEffect() {
doSomeDigging();
}
};
This one still creates a subclass in the background, but you might like it better.
i would use enums also, you can stuff a bunch of login in them. the maps let each player have whatever skills and stats they need. you can nest enums like this or that.
import java.util.Map;
import java.util.Random;
import java.util.TreeMap;
public class So36107587 {
enum Stat {
food,health,magic;
}
enum Skill {
heal,hurt,hunt;
static void apply(Skill skill,double amount,Player player) {
double a=amount*random.nextDouble(),x;
switch(skill) {
case heal:
x=player.stats.get(Stat.health);
player.stats.put(Stat.health,a+x);
break;
case hurt:
x=player.stats.get(Stat.health);
player.stats.put(Stat.health,a-x);
break;
case hunt:
x=player.stats.get(Stat.food);
player.stats.put(Stat.food,a+x);
break;
}
}
static final Random random=new Random();
}
static class Player {
Player() {
init();
}
void init() {
for(Stat stat:Stat.values())
stats.put(stat,1.);
for(Skill skill:Skill.values())
skills.put(skill,1.);
}
void apply(Skill skill,Player player) {
Skill.apply(skill,skills.get(skill),player);
}
#Override public String toString() {
return ""+skills+" "+stats;
}
final Map<Stat,Double> stats=new TreeMap<>();
final Map<Skill,Double> skills=new TreeMap<>();
}
public static void main(String[] args) {
Player player=new Player();
System.out.println(player);
player.apply(Skill.heal,player);
System.out.println(player);
player.apply(Skill.hunt,player);
System.out.println(player);
}
}
If I´m using an enum to determine the type of a task.
public enum TaskType {
TYPE_ONE("Type1"),TYPE_TWO("Type2"),TYPE_THREE("Type3");
private final String type;
private StageType(String type) {
this.type = type;
}
#Override
public String toString() {
return type;
}
}
how can I assure at one point in my Application
if(taskType == TaskType.TYPE_ONE) {
typeOneProcessing();
} else if(taskType == TaskType.TYPE_TWO) {
typeTwoProcessing();
} else if(taskType == TaskType.TYPE_THREE) {
typeThreeProcessing();
}
that every enum value is used?
I mean if I need to add a new TYPE_FOUR someday, I´d need to find every place in my code where I used the enum, so I ask myself if there is a better way so that I either avoid the enum and use some other concept or that I can ensure that every value of the enum is used in that piece of code.
There are findbugs type tools for doing that but you could consider removing the if-then-else completely and put the processing inside the enum. Here, adding a new TYPE_FOUR will force you to write it's doProcessing() method.
public interface DoesProcessing {
public void doProcessing();
}
public enum TaskType implements DoesProcessing {
TYPE_ONE("Type1") {
#Override
public void doProcessing() {
}
},
TYPE_TWO("Type2") {
#Override
public void doProcessing() {
}
},
TYPE_THREE("Type3") {
#Override
public void doProcessing() {
}
},
TYPE_FOUR("Type4") {
// error: <anonymous com.oldcurmudgeon.test.Test$TaskType$4> is not abstract and does not override abstract method doProcessing() in DoesProcessing
};
private final String type;
private TaskType(String type) {
this.type = type;
}
#Override
public String toString() {
return type;
}
}
public void test() {
DoesProcessing type = TaskType.TYPE_TWO;
type.doProcessing();
}
If you would prefer an abstract method then this works:
public enum TaskType {
TYPE_ONE("Type1") {
#Override
public void doProcessing() {
}
},
TYPE_TWO("Type2") {
#Override
public void doProcessing() {
}
},
TYPE_THREE("Type3") {
#Override
public void doProcessing() {
}
};
private final String type;
private TaskType(String type) {
this.type = type;
}
// Force them all to implement doProcessing.
public abstract void doProcessing();
#Override
public String toString() {
return type;
}
}
You could put the process method as an abstract method in TaskType, and then override it in every task in the enum. What would probably be a better idea is if you create an interface, something like:
public interface Task {
void process();
}
Then you either let your enum implement this interface. Or, probably better, you create concrete classes implementing this interface. One class for each of your task types.
I think you are saying that you are wanting the compiler to tell you that all of the enum's values are considered.
Unfortunately, Java doesn't support that.
You might think that you could write something like this:
public int method(TaskType t) {
switch (t) {
case TYPE_ONE: return 1;
case TYPE_TWO: return 2;
case TYPE_THREE: return 3;
}
// not reachable ... no return required
}
... and rely on the compiler to tell you if you left out one of the enum values in the switch cases.
Unfortunately, it doesn't work!! The above is a compilation error anyway. According to the JLS reachability rules, the switch statement needs a default: arm for that method to be valid. (Or you can add a return at the end ...)
There is a good reason for this oddity. The JLS binary compatibility rules say that adding a new value to an enum is a binary compatible change. That means that any code with switch statement that switches on an enum needs to still remain valid (executable) code after the addition of enum values. If method was valid to start with, it can't become invalid (because there is a return path with no return statement) after the binary compatible change.
In fact, this is how I would write the code above:
public int method(TaskType t) {
switch (t) {
case TYPE_ONE: return 1;
case TYPE_TWO: return 2;
case TYPE_THREE: return 3;
default:
throw new AssertionError("TaskType " + t + " not implemented");
}
// not reachable ... no return required
}
This doesn't pretend to be compile-time safe, but it is fail-fast, and it doesn't involve bad OO design.
AFAIK you can't do it "automatically".
To minimize the risk of forgetting to add an if/case for new value you could have one "service" class for each enum value and a factory which provides a specific service for enum value.
E.g. instead of:
void methodA(TaskType type) {
doSth();
switch(type) {
case TYPE_ONE:
foo1();
break;
case TYPE_TWO:
foo2();
break;
...
}
}
void methodB(TaskType type) {
doSthElse();
switch(type) {
case TYPE_ONE:
bar1();
break;
case TYPE_TWO:
bar2();
break;
...
}
}
do:
interface Service {
foo();
bar();
}
class ServiceFactory {
Service getInstance(TaskType type) {
switch(type) {
case TYPE_ONE:
return new TypeOneService();
case TYPE_TWO:
return new TypeTwoService();
default:
throw new IllegalArgumentException("Unsupported TaskType: " + type);
}
}
}
And then the methods above can be rewritten as follows:
void methodX(TaskType type) {
doSth();
ServiceFactory.getInstance(type).foo();
}
This way you have only one point where you have to add handling of new enum value.
HashMap<String, Integer> hm=new HashMap<String, Integer>();
...
if(taskType == TaskType.TYPE_ONE) {
typeOneProcessing();
hm.put(TaskType.TYPE_ONE, 1)
} else if(taskType == TaskType.TYPE_TWO) {
typeTwoProcessing();
hm.put(TaskType.TYPE_TWO, 1)
} else if(taskType == TaskType.TYPE_THREE) {
typeThreeProcessing();
hm.put(TaskType.TYPE_THREE, 1)
}
...
for (TaskType t : TaskType.values()) {
if(hm.get(t)!=1)
// Trigger the alarm
}
You can even count the times the element was count if you need it
You can do swich case on the enum, and fail if the default is hit:
switch(taskType ){
case TYPE_ONE: ... break;
case TYPE_TWO: ... break;
case TYPE_THREE: ... break;
default:
throw new IllegalStateException("Unsupported task type:"+taskType);
}
Let's say we have to check some set of rules before adding a new element in a collection. Elements are objects of a few similar types. All type specific features are encapsulated in subclasses of an abstract class. Collection contains objects of this abstract class. The rules apply conditions for types along with other constraints. For that reason the abstract superclass of items has additional type code. New element can be added to collection but due to additional rules other elements in collection can be removed or replaced.
In the code that needs to be refactored, validation of the rules is implemented as one long block of code with nested control flow statements. Validation of the type code breaks encapsulation. Separate branches of the control flow statements cannot be defined as method of corresponding subclasses of collection elements because them need to check type and make changes to collection.
additional facts regarding type code in my case:
type code does not affect the behaviour of class
type code is immutable
type code is used by ItemsManager to resolve some rules before to add
new element to collection.
How to eliminate type code and separate rules from types?
Here is example of such problem:
Type specific features of Items are encpsulated in AbstractItem subclasses.add method of ItemManager class breaks encapsulation.Rule: item of Type2 must be removed if new item of Type1 with the same value of SomeUsefull property is adding to collection.
For simplicity implementation of ICloneable and IComparable interfaces is omitted. In real world items in collection are immutable and cloneable and the system of rules is quite tangled.
abstract class AbstractItem {
private int Type; // this would like to eliminate
private int SomeUseful;
protected AbstractItem(int Type, int Value) {
this.Type = Type;
this.SomeUseful = Value;
}
public int getType() { return this.Type; }
public int getSomeUseful() { return this.SomeUseful; }
#Override
public String toString() {
return String.format("Item{Type=%d, Value=%d}", Type, SomeUseful);
}
}
class ItemType1 extends AbstractItem {
ItemType1(int Value) { super(1, Value); }
}
class ItemType2 extends AbstractItem {
ItemType2(int Value) { super(2, Value); }
}
class ItemManager {
private java.util.ArrayList<AbstractItem> ListOfItems;
public ItemManager(){
this.ListOfItems = new java.util.ArrayList<AbstractItem>();
}
public void add(final AbstractItem newItem) {
// this code breaks encapsulation
switch (newItem.getType()) {
case 1:
// do some type dependent operations
for(AbstractItem i: this.ListOfItems) {
if (i.getType()==2 && i.getSomeUseful()==newItem.getSomeUseful()) {
this.ListOfItems.remove(i);
break;
}
}
break;
case 2:
// do some other type dependent operations
break;
default:
// throw error
}
this.ListOfItems.add(newItem);
}
#Override
public String toString() {
String str = String.format("ItemsManager content");
for(AbstractItem i: this.ListOfItems) {
str += String.format("\n\tType = %d, Value = %d", i.getType(), i.getSomeUseful());
}
return str;
}
}
public class Example1 {
public static void main(String[] arg) {
System.out.println("Example 1");
ItemManager im = new ItemManager();
im.add(new ItemType1(1));
im.add(new ItemType2(2));
im.add(new ItemType2(3));
im.add(new ItemType1(3));
System.out.println(im.toString());
}
}
/*
Example 1
ItemsManager content
Type = 1, Value = 1
Type = 2, Value = 2
Type = 1, Value = 3
*/
Starting from #dbugger's answer you can push it further.
You can use Double Dispatch to hide the type code. Still not a perfect solution because the parent knows too much about its children, but the type code is gone now.
It is hard to tell what a better solution might be with the example code you have given, because when you simplified, you removed all the information about the items involved. There might be something there that could be used for discrimination in some other way, allowing you to get rid of the double dispatch with shoudBeRemovedBecauseType1.
Here is the altered onAdd method from type 1
#Override
public List<AbstractItem> onAdd(List<AbstractItem> list) {
for (AbstractItem item : list) {
if (item.shoudBeRemovedBecauseType1(this)) {
list.remove(item);
break;
}
}
return list;
}
A new method in the base class
public boolean shoudBeRemovedBecauseType1(ItemType1 itemType1)
{
return false;
}
overridden in the type 2 subclass
#Override
public boolean shoudBeRemovedBecauseType1(ItemType1 itemType1)
{
return getSomeUseful() == itemType1.getSomeUseful();
}
It's not ideal, but it's a step towards getting some encapsulation and killing the switch statement...
add an onAdd method to the base class that takes the list as a parameter.
public java.util.ArrayList<AbstractItem> onAdd(java.util.ArrayList<AbstractItem> list) { return list; }
then override it in the sub classes, for example...
#Override
public java.util.ArrayList<AbstractItem> onAdd(java.util.ArrayList<AbstractItem> list) {
for(AbstractItem i: this.ListOfItems) {
if (i.getType()==2 && i.getSomeUseful()==this.getSomeUseful()) {
list.remove(i);
break;
}
}
return list;
}
then rewrite the ItemManager add method to just call the sub classes' onAdd methods...
public void add(final AbstractItem newItem) {
this.ListOfItems = newItem.onAdd(this.ListOfItems);
this.ListOfItems.add(newItem);
}