Reputation: 720
I'm going to try my best to explain my problem using a scenario:
I have ClassA which contains only one non-static instance of ClassB, many non-static methods that affect that instance of ClassB that we can call EFFECTS and one last non-static getter method that returns that instance of ClassB.
I have ClassC which contains a non-static array of instances of ClassB. In ClassC I have two non-static methods, one that gets a single instance of ClassB from the array and another that sets a single instance of ClassB by the given index value.
What I'm trying to do: I want to have a ClassD that you can create instances of and which acts like an List of EFFECTS, and ClassD would have a non-static method that takes in ClassC as a parameter. That method then applies all these EFFECTS stored in the instance of ClassD to every instance of ClassB stored in the Array of the ClassC parameter provided in this method. Finally this method returns the ClassC with changed ClassB values in its array.
My current solution but I don't know how to get it to work is create an Enum with method references as constants? And then be able to store these in ClassD? And somehow call them? But I'm not extremely familiar with enums, and I've searched online for this but can't find out how to make this work.
Example of Scenario:
public class ClassA {
ClassB classB;
public ClassB get() { return classB; }
public void effectA() {
//affects classB instance
}
public void effectB() {
//affects classB instance
}
public void effectC() {
//affects classB instance
}
}
public class ClassB {
//Code for ClassB
}
public class ClassC {
ClassB[] classBs;
public ClassC(int size) {
classBs = new ClassB[size];
}
public ClassB getB(int index) {
return classBs[index];
}
public void setB(int index, ClassB classB) {
classBs[index] = classB;
}
public int getSize() {
return classBs.length;
}
}
public class ClassD {
ArrayList<Effects> effects;
public ClassD() {
effects = new ArrayList<Effects>();
}
public void addEffect(Effects effect, int effectIntensity) {
//???
}
public void removeEffect(int index) {
effects.remove(index);
}
public ClassC applyEffects(ClassC classC) {
for (int i = 0; i < classC.getSize(); i++) {
ClassB classB = classC.getB(i);
//Apply all effects from effects ArrayList to classB
classC.setB(i, classB);
}
return classC;
}
}
public enum Effects {
//??? Code related to effect methods from ClassA
}
Where the question marks are that's where I don't know how to do this to achieve what I'm trying to do.
Upvotes: 0
Views: 5081
Reputation: 37855
I'm going to shorten your example because you have a lot of things going on that I don't think really apply to the question you've asked.
enum
constants are basically just public static final
instances of the enum
class. Therefore you are able to declare abstract
methods and override them on each constant.
enum ClassAEffect {
A { @Override void apply(ClassA theA) { theA.effectA(); } },
B { @Override void apply(ClassA theA) { theA.effectB(); } },
C {
@Override
void apply(ClassA theA) {
theA.effectC();
}
};
abstract void apply(ClassA theA);
}
class ClassD {
List<ClassAEffect> effects = new ArrayList<>();
void add(ClassAEffect effect) { effects.add(effect); }
void apply(List<ClassA> list) {
for(ClassA theA : list)
for(ClassAEffect effect : effects)
effect.apply(theA);
}
}
ClassD theD = new ClassD();
theD.add(ClassAEffect.B);
theD.apply(Arrays.asList(new ClassA()));
enum
may or may not be appropriate. For example if your design demanded effects for multiple classes, it may be much better to use regular interfaces.
interface Effect<T> {
void apply(T theT);
}
Effect<ClassA> classAEffectA = new Effect<>() {
@Override
public void apply(ClassA theA) {
theA.effectA();
}
};
As another answer notes, this is basically like command pattern and Wikipedia contains a Java example strikingly similar to your own.
Also, in Java 8, you may use method references directly.
class ClassD implements Consumer<List<ClassA>> {
List<Consumer<ClassA>> effects = new ArrayList<>();
void add(Consumer<ClassA> effect) { effects.add(effect); }
@Override
public void accept(List<ClassA> theList) {
for(ClassA theA : theList)
for(Consumer<ClassA> effect : effects)
effect.accept(theA);
}
}
ClassD theD = new ClassD();
// ClassA::effectB implicitly creates a Consumer<ClassA>
// that calls effectB on the ClassA that is passed to it
theD.add(ClassA::effectB);
theD.accept(Arrays.asList(new ClassA()));
Upvotes: 2
Reputation: 683
Maybe you could use a variant of the command pattern for this?
Class D would be the Invoker and save all the effects (commands) that you want to execute in an array/list. If you don't want to add effects during runtime you could add them in the constructor.
ClassD would have a method executeAllOn(ClassC) that executes all the effects on the objects of ClassB in the ClassC array.
Reference: Command Pattern [wikipedia]
Edit after I saw your example, would look something like this:
public class ClassD {
ArrayList<Effect> effects;
HashMap<Effect, Integer> intensity;
public ClassD() {
effects = new ArrayList<Effects>();
}
public void addEffect(Effects effect, int effectIntensity) {
effects.add(effect)
intensity.put(effect, effectIntensity)
}
public void removeEffect(int index) {
effects.remove(index);
intensity.remove(effects.get(index))
}
public ClassC applyEffects(ClassC classC) {
for (int i = 0; i < classC.getSize(); i++) {
ClassB classB = classC.getB(i);
for (Effect effect : effects) {
effect.execute(classB, intensity.get(effect))
}
classC.setB(i, classB);
}
return classC;
}
}
Upvotes: 1