is this java interface tactic sound? - java

I've been thinking about implementing a certain tactic for my code.
This is my setup:
I've got an interface called "Object".
Then I've got an interface called "Entity" that extends "Object".
From entity then springs countless implementations, like "army", "city", "lemon", etc.
Now, I want to gather all of these Objects into some form of map. Then from that map I want to get the particular implementation of "Object".
My thought out solution for this is as follows:
Object has method :
public Entity getEntity()
All implementations of Object returns null, while Entity returns itself.
Likewise, in entity I'd have:
public Army getArmy()
public City getCity()
That way, I can simply pull an object from the map and get the specific class from it with a series of null checks, like so;
Object o = Objects.getObject(2dCoordinates);
Entity e = o.getEntity();
if (e != null){
Army a = e.getArmy();
if (a != null)
a.armySpecificMethod();
}
All without using "instanceof" and casting, which I hate.
The question is whether there's some unforeseen problem about this? I'd rather learn from someone that knows before refactoring my code and find out for myself.

You asked if there are any pitfalls to your strategy. I would say no, since C# uses the same strategy with their as keyword. Example: e as Army would return e if e is-a Army, or null otherwise. It is basicly a cast that instead of failing returns null.
However you don't have to implement this functionality using interfaces, you can write your own as method for example like this:
static <T> T as(Class<T> clazz, Object obj) {
if (clazz.isInstance(obj)) {
return (T) obj;
}
return null;
}
usage:
Object o = Objects.getObject(2dCoordinates);
Entity e = as(Entity.class, o);
if (e != null) {
Army a = as(Army.class, e);
if (a != null)
a.armySpecificMethod();
}

Another approach would be to register callbacks/strategies to be invoked on particular events. Something like that:
public interface OnMapClicked<T> {
void onItemSelected(T item);
}
And your GameMap (or whatever) implementation would be:
public GameMap {
private final Map<Class<?>, OnMapClicked> listeners = new HashMap<>();
public <T> void registerListener(Class<? extends T> type, OnMapClicked<T> listener) {
listeners.put(type, listener);
}
//
private void onMapClicked(Coordinates coordinates) {
Object object = findObject(coordinates);
listeners.get(object.getClass()).onItemSelected(object);
}
}
That's very rough untested implementation, but hopefully you got the idea. There is one usage of non-generic instance here (in onMapClicked), but it should be safe, since we're checking the input type in registerListener.

Related

Call method of unknown object

I have two ArrayLists - ArrayList1 and ArrayList2. Each of them is filled with objects - Object1 and Object2, respectively.
Both of these objects have method 'getText'.
Object1:
public String getText() { return "1";}
Object2:
public String getText() { return "2";}
At certain point I would like to loop through each of these lists using the same method (just with different parameter).
loopThroughList(1)
loopThroughList(2)
What is the syntax if I want to call a method, but I don't know which object it is going to be? This is the code I have so far:
for (Object o : lists.getList(listNumber)) {
System.out.println(o.getText());
}
It says Cannot resolve method getText. I googled around and found another solution:
for (Object o : lists.getList(listNumber)) {
System.out.println(o.getClass().getMethod("getText"));
}
But this gives me NoSuchMethodException error. Even though the 'getText' method is public.
EDIT: To get the correct list, I am calling the method 'getList' of a different object (lists) that returns either ArrayList1 or ArrayList2 (depending on the provided parameter).
class Lists
public getList(list) {
if (list == 1) {
return ArrayList1;
}
else if (list == 2) {
return ArrayList2;
}
}
Define an interface for the getText method
public interface YourInterface {
String getText();
}
Implement the interface on the respective classes
public class Object1 implements YourInterface {
#Override
public String getText() {
return "1";
}
}
public class Object2 implements YourInterface {
#Override
public String getText() {
return "2";
}
}
Modify your getList method to return List<YourInterface>
public static List<YourInterface> getList(int list){
List<YourInterface> result = new ArrayList<>();
if(list == 1){
// your initial type
List<Object1> firstList = new ArrayList<>();
result.addAll(firstList);
} else {
// your initial type
List<Object2> secondList = new ArrayList<>();
result.addAll(secondList);
}
return result;
}
Declaration for loopThroughList
public static void loopThroughList(List<YourInterface> list){
list.forEach(yourInterface -> System.out.println(yourInterface.getText()));
}
Sample usage.
public static void main(String[] args) {
loopThroughList(getList(1));
loopThroughList(getList(2));
}
Interfaces work great here, but there a couple of other options if you're dealing with legacy code and cannot use interfaces.
First would be to cast the list items into their respective types:
for (Object o : lists.getList(listNumber)) {
if(o instanceof Object1) {
Object1 o1 = (Object1)o;
System.out.println(o1.getText());
}
else if(o instanceof Object2) {
Object1 o2 = (Object2)o;
System.out.println(o2.getText());
}
else {
System.out.println("Unknown class");
}
}
You can also use reflection to see if the object has a getText method and then invoke it:
for (Object o : lists.getList(listNumber)) {
try {
System.out.println(o.getClass().getDeclaredMethod("getName").invoke(o));
}
catch(Exception e) {
System.out.println("Object doesn't have getText method");
}
}
This is awful. Can you elaborate on what specifically you are trying to do? Java is strong typed by design, and you are trying to get around it. Why? Instead of Object, use the specific class, or interface as previously suggested. If that's not possible, and you must use lists of Objects, use instanceof and casting eg:
for (Object o : lists.getList(listNumber)) {
if (o instanceof Object1) {
Object1 o1 = (Object1) o;
System.out.println(o1.getText());
} else if (o instanceof Object2) {
Object2 o2 = (Object2) o;
System.out.println(o2.getText());
}
}
This is where interfaces come in.
interface HasText {
public String getText();
}
class Object1 implements HasText {
#Override
public String getText() {
return "1";
}
}
class Object2 implements HasText {
#Override
public String getText() {
return "2";
}
}
private void test() {
List<HasText> list = Arrays.asList(new Object1(), new Object2());
for (HasText ht : list) {
System.out.println(ht);
}
}
If one of your objects is not in your control you can use a Wrapper class.
class Object3DoesNotImplementHasText {
public String getText() {
return "3";
}
}
class Object3Wrapper implements HasText{
final Object3DoesNotImplementHasText it;
public Object3Wrapper(Object3DoesNotImplementHasText it) {
this.it = it;
}
#Override
public String getText() {
return it.getText();
}
}
private void test() {
List<HasText> list = Arrays.asList(new Object1(), new Object2(), new Object3Wrapper(new Object3DoesNotImplementHasText()));
for (HasText ht : list) {
System.out.println(ht);
}
}
Just to add more to this answer and give you some more to think on this (Will try to do it in a simple, non-formal way). Using interfaces is the proper way of doing such operation. However, I want to stand on the "bad idea":
for (Object o : lists.getList(listNumber)) {
System.out.println(o.getClass().getMethod("getText"));
}
What you are doing here, is using a mechanism called Reflection:
Reflection is a feature in the Java programming language. It allows an
executing Java program to examine or "introspect" upon itself, and
manipulate internal properties of the program. For example, it's
possible for a Java class to obtain the names of all its members and
display them.
What you actually attempted, is using that mechanism, to retrieve the method through a Class reflection object instance of your Class (sounds weird, isn't it?).
From that perspective, you need to think that, if you want to invoke your method, you now have, in a sense, a meta-Class instance to manipulate your objects. Think of it like an Object that is one step above your Objects (Similarly to a dream inside a dream, in Inception). In that sense, you need to retrieve the method, and then invoke it in a different (meta-like) way:
java.lang.reflect.Method m = o.getClass().getMethod("getText");
m.invoke(o);
Using that logic, you could possibly iterate through the object list, check if method exists, then invoke your method.
This is though a bad, BAD idea.
Why? Well, the answer relies on reflection itself: reflection is directly associated with runtime - i.e. when the program executes, practically doing all things at runtime, bypassing the compilation world.
In other words, by doing this, you are bypassing the compilation error mechanism of Java, allowing such errors happen in runtime. This can lead to unstable behavior of the program while executing - apart from the performance overhead using Reflection, which will not analyze here.
Side note: While using reflection will require the usage of Checked Exception handling, it still is not a good idea of doing this - as you practically try to duck tape a bad solution.
On the other hand, you can follow the Inheritance mechanism of Java through Classes and Interfaces - define an interface with your method (let's call it Textable), make sure that your classes implement it, and then use it as your base object in your list declaration (#alexrolea has implemented this in his answer, as also #OldCurmudgeon has).
This way, your program will still make the method call decision making at Runtime (via a mechanism called late binding), but you will not bypass the compilation error mechanism of Java. Think about it: what would happen if you define a Textable implementation without providing the class - a compile error! And what if you set a non-Textable object into the list of Textables? Guess what! A compile error again. And the list goes on....
In general, avoid using Reflection when you are able to do so. Reflection is useful in some cases that you need to handle your program in such a meta-way and there is no other way of making such things. This is not the case though.
UPDATE: As suggested by some answers, you can use instanceof to check if you have a specific Class object instance that contains your method, then invoke respectively. While this seems a simple solution, it is bad in terms of scaling: what if you have 1000 different classes that implement the same method you want to call?
your objects have to implement a common interface.
interface GetTextable {
String getText();
}
class One implements GetTextable {
private final String text;
public One(final String text) {
this.text = text;
}
public String getText() {
return this.text;
}
}
class Two implements GetTextable {
private final String text;
public Two(final String text) {
this.text = text;
}
public String getText() {
return this.text;
}
}
#Test
public void shouldIterate() throws Exception {
List<GetTextable> toIterate = Arrays.asList(new One("oneText"), new Two("twoText"));
for(GetTextable obj: toIterate) {
System.out.println(obj.getText());
}
}

How to use java reflection to return a Collection that contains something other then Objects

So my problem is that im currently trying to use java's reflection to traverse a tree like structure. The problem is the only thing i know about each structure is that it can contain one of three things. Strings (the leaf's) Other Objects, Or Lists of other objects. Using reflection i want to do a DFS of the tree until i find a node that im looking for. My problem seems to be that when i use reflection to get a field that happens to be of type List i get back List and i am unable to down cast the the correct type. here are some samples i have tried.
Using Fields
Object returnObj = new Object();
Field field = object.getClass().getDeclaredField(fieldClassName);
field.setAccessible(true);
List<DistributionPartnerRoleType> test = (List<DistributionPartnerRoleType>) field.get(object);
And using Methods
String methodName = "get" + Character.toUpperCase(fieldClassName.charAt(0)) + fieldClassName.substring(1);
Method[] getters = object.getClass().getMethods();
Method getter = getMethod(getters, methodName);
Type returnType = getter.getGenericReturnType();
if(returnType instanceof ParameterizedType){
Type actualType = ((ParameterizedType) returnType).getActualTypeArguments()[0];
Class actualClass = (Class) actualType;
returnObj = getter.invoke(object, null);
List<Object> newList = new ArrayList<Object>();
for(Object obj : (List<Object>)returnObj){
newList.add(actualClass.cast(obj));
}
returnObj = newList;
}
Im aware that the problem is that the objects are truly of type Object but the function and fields are explicitly of type List as declared in the code
protected List<DistributionPartnerRoleType> distributionPartnerRole;
public List<DistributionPartnerRoleType> getDistributionPartnerRole() {
if (distributionPartnerRole == null) {
distributionPartnerRole = new ArrayList<DistributionPartnerRoleType>();
}
return this.distributionPartnerRole;
}
If anyone knows of a solution for this problem that would be great, Or if i need to go about a different method other then reflection.
To sum up my problem. Invoke is returning a List But the objects inside the list are not actually of the type this function returns they are of type java.lang.Object Is there any way to get around this or is dynamic access of the lists objects not possible?
I don't think use of reflection is a good idea in this case. In my view there are very few appropriate use cases. It's often a sign that you need to rethink your approach.
In this case I suggest you look at the Visitor design pattern. The visitor itself can include the logic for a depth-first search as well as dealing with the various types of data in the nodes.
In your case the pattern might look something like:
interface Node {
void accept(NodeVisitor visitor);
}
class StringNode implements Node {
public String getValue();
public void accept(NodeVisitor visitor) {
visitor.visit(this);
}
}
class IntegerNode implements Node {
public int geValue();
public void accept(NodeVisitor visitor) {
visitor.visit(this);
}
}
class CompositeNode implements Node {
public void forEachChild(Consumer<Node> action);
public void accept(NodeVisitor visitor) {
visitor.visit(this);
}
}
interface NodeVisitor {
default void visit(StringNode node) {}
default void visit(IntegerNode node) {}
default void visit(CompositeNode node) {}
}
Now your search algorithm might look like:
class IntegerSearch implements NodeVisitor {
private final int target;
private final List<IntegerNode> results = new ArrayList<>();
void visit(IntegerNode node) {
if (node.getValue() == target)
results.add(node);
}
}
void visit(CompositeNode node) {
node.forEachChild(child -> child.accept(this));
}
}
No reflection, casting or other dodgy idioms!
This might not exactly match your case (e.g. perhaps the nodes with values are also composites?) but hopefully you see the general pattern for avoiding reflection.
There is a deeper problem here, As stated by Louis Wasserman, reflection should not be causing this and there seems to be a problem with my code in another location.

Using enum to implement multitons in Java

I would like to have a limited fixed catalogue of instances of a certain complex interface. The standard multiton pattern has some nice features such as lazy instantiation. However it relies on a key such as a String which seems quite error prone and fragile.
I'd like a pattern that uses enum. They have lots of great features and are robust. I've tried to find a standard design pattern for this but have drawn a blank. So I've come up with my own but I'm not terribly happy with it.
The pattern I'm using is as follows (the interface is highly simplified here to make it readable):
interface Complex {
void method();
}
enum ComplexItem implements Complex {
ITEM1 {
protected Complex makeInstance() { return new Complex() { ... }
},
ITEM2 {
protected Complex makeInstance() { return new Complex() { ... }
};
private Complex instance = null;
private Complex getInstance() {
if (instance == null) {
instance = makeInstance();
}
return instance;
}
protected void makeInstance() {
}
void method {
getInstance().method();
}
}
This pattern has some very nice features to it:
the enum implements the interface which makes its usage pretty natural: ComplexItem.ITEM1.method();
Lazy instantiation: if the construction is costly (my use case involves reading files), it only occurs if it's required.
Having said that it seems horribly complex and 'hacky' for such a simple requirement and overrides enum methods in a way which I'm not sure the language designers intended.
It also has another significant disadvantage. In my use case I'd like the interface to extend Comparable. Unfortunately this then clashes with the enum implementation of Comparable and makes the code uncompilable.
One alternative I considered was having a standard enum and then a separate class that maps the enum to an implementation of the interface (using the standard multiton pattern). That works but the enum no longer implements the interface which seems to me to not be a natural reflection of the intention. It also separates the implementation of the interface from the enum items which seems to be poor encapsulation.
Another alternative is to have the enum constructor implement the interface (i.e. in the pattern above remove the need for the 'makeInstance' method). While this works it removes the advantage of only running the constructors if required). It also doesn't resolve the issue with extending Comparable.
So my question is: can anyone think of a more elegant way to do this?
In response to comments I'll tried to specify the specific problem I'm trying to solve first generically and then through an example.
There are a fixed set of objects that implement a given interface
The objects are stateless: they are used to encapsulate behaviour only
Only a subset of the objects will be used each time the code is executed (depending on user input)
Creating these objects is expensive: it should only be done once and only if required
The objects share a lot behaviour
This could be implemented with separate singleton classes for each object using separate classes or superclasses for shared behaviour. This seems unnecessarily complex.
Now an example. A system calculates several different taxes in a set of regions each of which has their own algorithm for calculting the taxes. The set of regions is expected to never change but the regional algorithms will change regularly. The specific regional rates must be loaded at run time via remote service which is slow and expensive. Each time the system is invoked it will be given a different set of regions to calculate so it should only load the rates of the regions requested.
So:
interface TaxCalculation {
float calculateSalesTax(SaleData data);
float calculateLandTax(LandData data);
....
}
enum TaxRegion implements TaxCalculation {
NORTH, NORTH_EAST, SOUTH, EAST, WEST, CENTRAL .... ;
private loadRegionalDataFromRemoteServer() { .... }
}
Recommended background reading: Mixing-in an Enum
Seems fine. I would make initialization threadsafe like this:
enum ComplexItem implements Complex {
ITEM1 {
protected Complex makeInstance() {
return new Complex() { public void method() { }};
}
},
ITEM2 {
protected Complex makeInstance() {
return new Complex() { public void method() { }}
};
private volatile Complex instance;
private Complex getInstance() {
if (instance == null) {
createInstance();
}
return instance;
}
protected abstract Complex makeInstance();
protected synchronized void createInstance() {
if (instance == null) {
instance = makeInstance();
}
}
public void method() {
getInstance().method();
}
}
The modifier synchronized only appears on the createInstance() method, but wraps the call to makeInstance() - conveying threadsafety without putting a bottleneck on calls to getInstance() and without the programmer having to remember to add synchronized to each to makeInstance() implementation.
This works for me - it's thread-safe and generic. The enum must implement the Creator interface but that is easy - as demonstrated by the sample usage at the end.
This solution breaks the binding you have imposed where it is the enum that is the stored object. Here I only use the enum as a factory to create the object - in this way I can store any type of object and even have each enum create a different type of object (which was my aim).
This uses a common mechanism for thread-safety and lazy instantiation using ConcurrentMap of FutureTask.
There is a small overhead of holding on to the FutureTask for the lifetime of the program but that could be improved with a little tweaking.
/**
* A Multiton where the keys are an enum and each key can create its own value.
*
* The create method of the key enum is guaranteed to only be called once.
*
* Probably worth making your Multiton static to avoid duplication.
*
* #param <K> - The enum that is the key in the map and also does the creation.
*/
public class Multiton<K extends Enum<K> & Multiton.Creator> {
// The map to the future.
private final ConcurrentMap<K, Future<Object>> multitons = new ConcurrentHashMap<K, Future<Object>>();
// The enums must create
public interface Creator {
public abstract Object create();
}
// The getter.
public <V> V get(final K key, Class<V> type) {
// Has it run yet?
Future<Object> f = multitons.get(key);
if (f == null) {
// No! Make the task that runs it.
FutureTask<Object> ft = new FutureTask<Object>(
new Callable() {
public Object call() throws Exception {
// Only do the create when called to do so.
return key.create();
}
});
// Only put if not there.
f = multitons.putIfAbsent(key, ft);
if (f == null) {
// We replaced null so we successfully put. We were first!
f = ft;
// Initiate the task.
ft.run();
}
}
try {
/**
* If code gets here and hangs due to f.status = 0 (FutureTask.NEW)
* then you are trying to get from your Multiton in your creator.
*
* Cannot check for that without unnecessarily complex code.
*
* Perhaps could use get with timeout.
*/
// Cast here to force the right type.
return type.cast(f.get());
} catch (Exception ex) {
// Hide exceptions without discarding them.
throw new RuntimeException(ex);
}
}
enum E implements Creator {
A {
public String create() {
return "Face";
}
},
B {
public Integer create() {
return 0xFace;
}
},
C {
public Void create() {
return null;
}
};
}
public static void main(String args[]) {
try {
Multiton<E> m = new Multiton<E>();
String face1 = m.get(E.A, String.class);
Integer face2 = m.get(E.B, Integer.class);
System.out.println("Face1: " + face1 + " Face2: " + Integer.toHexString(face2));
} catch (Throwable t) {
t.printStackTrace(System.err);
}
}
}
In Java 8 it is even easier:
public class Multiton<K extends Enum<K> & Multiton.Creator> {
private final ConcurrentMap<K, Object> multitons = new ConcurrentHashMap<>();
// The enums must create
public interface Creator {
public abstract Object create();
}
// The getter.
public <V> V get(final K key, Class<V> type) {
return type.cast(multitons.computeIfAbsent(key, k -> k.create()));
}
}
One thought about this pattern: the lazy instantiation isn't thread safe. This may or may not be okay, it depends on how you want to use it, but it's worth knowing. (Considering that enum initialisation in itself is thread-safe.)
Other than that, I can't see a simpler solution that guarantees full instance control, is intuitive and uses lazy instantiation.
I don't think it's an abuse of enum methods either, it doesn't differ by much from what Josh Bloch's Effective Java recommends for coding different strategies into enums.

Anything wrong with instanceof checks here?

With the introduction of generics, I am reluctant to perform instanceof or casting as much as possible. But I don't see a way around it in this scenario:
for (CacheableObject<ICacheable> cacheableObject : cacheableObjects) {
ICacheable iCacheable = cacheableObject.getObject();
if (iCacheable instanceof MyObject) {
MyObject myObject = (MyObject) iCacheable;
myObjects.put(myObject.getKey(), myObject);
} else if (iCacheable instanceof OtherObject) {
OtherObject otherObject = (OtherObject) iCacheable;
otherObjects.put(otherObject.getKey(), otherObject);
}
}
In the above code, I know that my ICacheables should only ever be instances of MyObject, or OtherObject, and depending on this I want to put them into 2 separate maps and then perform some processing further down.
I'd be interested if there is another way to do this without my instanceof check.
Thanks
You could use double invocation. No promises it's a better solution, but it's an alternative.
Code Example
import java.util.HashMap;
public class Example {
public static void main(String[] argv) {
Example ex = new Example();
ICacheable[] cacheableObjects = new ICacheable[]{new MyObject(), new OtherObject()};
for (ICacheable iCacheable : cacheableObjects) {
// depending on whether the object is a MyObject or an OtherObject,
// the .put(Example) method will double dispatch to either
// the put(MyObject) or put(OtherObject) method, below
iCacheable.put(ex);
}
System.out.println("myObjects: "+ex.myObjects.size());
System.out.println("otherObjects: "+ex.otherObjects.size());
}
private HashMap<String, MyObject> myObjects = new HashMap<String, MyObject>();
private HashMap<String, OtherObject> otherObjects = new HashMap<String, OtherObject>();
public Example() {
}
public void put(MyObject myObject) {
myObjects.put(myObject.getKey(), myObject);
}
public void put(OtherObject otherObject) {
otherObjects.put(otherObject.getKey(), otherObject);
}
}
interface ICacheable {
public String getKey();
public void put(Example ex);
}
class MyObject implements ICacheable {
public String getKey() {
return "MyObject"+this.hashCode();
}
public void put(Example ex) {
ex.put(this);
}
}
class OtherObject implements ICacheable {
public String getKey() {
return "OtherObject"+this.hashCode();
}
public void put(Example ex) {
ex.put(this);
}
}
The idea here is that - instead of casting or using instanceof - you call the iCacheable object's .put(...) method which passes itself back to the Example object's overloaded methods. Which method is called depends on the type of that object.
See also the Visitor pattern. My code example smells because the ICacheable.put(...) method is incohesive - but using the interfaces defined in the Visitor pattern can clean up that smell.
Why can't I just call this.put(iCacheable) from the Example class?
In Java, overriding is always bound at runtime, but overloading is a little more complicated: dynamic dispatching means that the implementation of a method will be chosen at runtime, but the method's signature is nonetheless determined at compile time. (Check out the Java Language Specification, Chapter 8.4.9 for more info, and also check out the puzzler "Making a Hash of It" on page 137 of the book Java Puzzlers.)
Is there no way to combine the cached objects in each map into one map? Their keys could keep them separated so you could store them in one map. If you can't do that then you could have a
Map<Class,Map<Key,ICacheable>>
then do this:
Map<Class,Map<Key,ICacheable>> cache = ...;
public void cache( ICacheable cacheable ) {
if( cache.containsKey( cacheable.getClass() ) {
cache.put( cacheable.getClass(), new Map<Key,ICacheable>() );
}
cache.get(cacheable.getClass()).put( cacheable.getKey(), cacheable );
}
You can do the following:
Add a method to your ICachableInterface interface that will handle placing the object into one of two Maps, given as arguments to the method.
Implement this method in each of your two implementing classes, having each class decide which Map to put itself in.
Remove the instanceof checks in your for loop, and replace the put method with a call to the new method defined in step 1.
This is not a good design, however, because if you ever have another class that implements this interface, and a third map, then you'll need to pass another Map to your new method.

OOP classes design

My question concerns classes design in OOP. Let say we have ItemBase which is parent class for Canceled, Modified and Added class. We also have DueToBase class - parent of Provider and Distributor.
ItemBase may be changed due to DueToBase class.
Assume that ItemBase has property of type DueToBase, and DueToBase has interface method called compute(). Compute algorithm is RELATED to the specific ItemBase derived class. So we have six different possible combinations of ItemBase-DueToBase relationship.
Example.
ItemBase ib = new Added();
ib.changed = new Provider(ib);
ib.changed.compute();
My question is how should relationship between ItemBase and DueToBase be built in real object oriented programming ? I do not see swich/case or if condition clause in compute method for checking which type of instance ItemBase is.
It gets even worse if DueToBase has another XXXBase class inside which has another interface method YYY() which algorithm depends on the specific instance of DueToBase (and even on the ItemBase).
How to deal with such cases ? Is there any good programming pattern for such things ? Maybe direction I followed is bad. I would appreciate for your assistance.
maybe that my diagram was not clear. The problem is with following...
pseudocode:
doSomething(){
if(itemBase instanceof Cancelled){
if(dueToBase instanceof Provider)
algorithm1();
else if(dueToBase instanceof Company)
algorithm2();
}else if(itemBase instanceof Modified){
if(dueToBase instanceof Provider)
algorithm3();
else if(dueToBase instanceof Company)
algorithm4();
}else if(itemBase instanceof Added){
if(dueToBase instanceof Provider)
algorithm5();
else if(dueToBase instanceof Company)
algorithm6();
}
}
it gets even worse with deeper if clauses.
Your ItemBase class can be an abstract class with compute() method in it, and all the child classes can have their own implementation.
So later you can do something like this,
ItemBase ib = new Added();
ib.changed = new Provider(ib);
ib.changed.compute();
Now, when you will call compute method on ib.changed, it will execute compute implementation of Added class.
In your case, due to base class, Add a instance variable which distinguish between Provider and Company. Something like a boolean flag or int.
Then instead of using dueToBase instanceof Provider you can just create if statement. So your updated pseudo code will decreased to few line. Something like this,
doSomething(){
if(dueToBase.isProvider) {
algorithm1(); //execute if Provider
} else {
algorithm2(); //execute if Company
}
}
Now the complexity to choose compute will be handled by Abstract pattern and then you just have to worry about whether it is company or provider.
the better way will be:
interface Algorithm {
void executeAlgorithm();
}
and have classes, that implement Algorithm interface, instead of functions. Algorithm1, Algorithm2, Algorithm3 and so on.
and have table:
Algorithm[,] algorithmTable = { { new Algorithm1(), new Algorithm2() },
{ new Algorithm3(), new Algorithm4() },
{ new Algorithm5(), new Algorithm6() }
};
and have maps
Map< Class<?> , Integer > itemBaseMap = new HashMap<>();
Map< Class<?> , Integer > dueToBaseMap = new HashMap<>();
and somewhere build this maps
itemBaseMap.add( Canceled.class , 0 );
itemBaseMap.add( Modified.class , 1 );
itemBaseMap.add( Added.class , 2 );
dueToBaseMap.add( Provider.class, 0 );
dueToBaseMap.add( Company.class, 1 );
and in doSomething method you can write
void doSomething( ItemBase itemBase, DueToBase dueToBase ) {
Integer itemBaseIndex = itemBaseMap.get( itemBase.getClass() );
Integer dueToBaseIndex = dueToBaseMap.get( dueToBase.getClass() );
Algorithm algorithm = algorithmTable[ itemBaseIndex, dueToBaseIndex ];
algorithm.executeAlgorithm();
}
I'd say Strategy Pattern
abstract class ItemBase {
public DueToBase myDueToBase;
public void partOfTheAlgorithmThatOnlySpecificIBKnows();
}
class Modified extends ItemBase {
public void partOfTheAlgorithmThatOnlySpecificIBKnows() {
//stuff only Modified knows
}
}
abstract class DueToBase {
public void partOfTheAlgorithmThatOnlySpecificDTBKnows();
}
class Provider extends DueToBase {
//relevant code
public ItemBase myItemBase;
public void partOfTheAlgorithmThatOnlySpecificDTBKnows(){
//stuff only provider knows
}
public void compute() {
//you can also pass this but pointless since you all ready have the reference
myItemBase.partOfTheAlgorithmThatOnlySpecificIBKnows();
//some more code
}
}
ItemBase ib = new Added();
ib.changed = new Provider(ib);
ib.changed.compute();
In the example this will call:
1. compute on Provider
2. part of the algorithm that Modified knows how to calculate
3. rest of the code for the algorithm
so at the compute function you have all the specific methods you need for the inherited classes and you can vary the algorithm in the compute() function.
If this doesn't solve your problem you might just have to figure a new design looking at the requirements as Owl said.
Also has no ifs but has more methods in which you are kind of doing the same thing has with the ifs, you are just letting the Inheritance mechanism do it for you.
you can do so:
interface Algorithm {
void executeAlgorithm(DueToBase dueToBase);
}
and have map
Map<Class, Algorithm> algorithmMap = new HashMap<Class, Algorithm>();
you will have classes for each algorithm
for example:
/**
* this class is, for example, when itemBase instanceof Cancelled
*/
class Algorithm1 implements Algorithm {
public void executeAlgorithm(DueToBase dueToBase) {
if ( dueToBase instanceof Provider ) {
someAlgorithm(); // the algorithm specified somewhere, for provider
} else if ( dueToBase instanceof Company ) {
anotherAlgorithm(); // the algorithm or Company.
}
// this someAlgorithm() and anotherAlgorithm() are not same for different Algorithm classes
}
somewhere you must build algorithmMap.
algorithmMap.add( Cancelled.class , new Algorithm1() );
algorithmMap.add( Modified.class , new Algorithm2() );
algorithmMap.add( Added.class , new Algorithm3() );
and in doSomething method you won't have to write if-else blocks
doSomething() {
Algorithm algorithm = algorithmMap.get( itemBase.getClass() );
algorithm.executeAlgorithm(dueToBase);
}
in my opinion this is one of good oop solutions of this problem.

Categories

Resources