Can somebody recommend a java 8 pattern to replace a switch statement? - java

I have following code:
public class A {
private String type;
String getType() { return type;}
}
Now in many code places I have code like this
switch (a.geType()) {
case "A" : return new Bla();
case "B" : return new Cop();
}
or somewhere else
switch (a.geType()) {
case "A" : return new Coda();
case "B" : return new Man();
}
(Note that I know I should use an Enumeration in production code).
What I want to achive is that when a new type is added to class A the compiler should flag all the switch statements that need to be adjusted?
Is there a java idiomatic way to do this?

when a new type is added to class A the compiler should flag all the switch statements that need to be adjusted?
A good approach to this would be replacing switch statements with a more robust implementation of multiple dispatch, such as the Visitor Pattern:
interface VisitorOfA {
Object visitA(A a);
Object visitB(B b);
}
class A {
Object accept(VisitorOfA visitor) {
return visitor.visitA(this);
}
}
class B extends A {
Object accept(VisitorOfA visitor) {
return visitor.visitB(this);
}
}
With this infrastructure in place, you can remove your switch statements, replacing them with implementations of the visitor:
Object res = a.accept(new VisitorOfA() {
public Object visitA(A a) { return new Bla(); }
public Object visitB(B b) { return new Cop(); }
});
When you add a new subtype to A, say, class C, all you need to do is adding a new method to VisitorOfA:
Object visitC(C c);
Now the compiler will spot all places where this new method has not been implemented, helping you avoid problems at runtime.

Don't forget about good old-fashioned polymorphism. Having a "type" field with switch statements in a class is often a smell that indicates that subclassing might be useful. Consider:
public abstract class CommonSuperClass {
public abstract One getOne();
public abstract Two getTwo();
}
public class A extends CommonSuperClass {
#Override public One getOne() { return new Bla(); }
#Override public Two getTwo() { return new Coda(); }
}
public class B extends CommonSuperClass {
#Override public One getOne() { return new Cop(); }
#Override public Two getTwo() { return new Man(); }
}
If you were to add a new subclass C, you're required to provide implementations for the abstract methods (unless you make C itself be abstract).

You could have a map of string / suppliers:
Map<String, Supplier<Object>> map = new HAshMap<> ();
map.put("A", Bla::new);
map.put("B", Cop::new);
And your sample code would become:
return map.get(a.getType()).get(); //need null check

In perspective of abstraction, there is another approach for you to use. One way is via Polymorphism as shown here.
Some simple example:
public void EverythingYouWant (Animal animal) {
return animal.move();
}
When it's more about refactoring replace type code/checking with State/Strategy patterns. It's good solution to first consider is there any reason that prevents subclassing.

Related

Returning object depending on a value in a generic way

Consider I have many classes, that all inherit from the same class :
public class A
{
...
}
public class AA extends A
{
...
}
public class AB extends A
{
...
}
public class AC extends A
{
...
}
And then in some other part of the code, I would like to return one of the child class, depending on a value sent to that function, as follow :
public A getChild(int value, Object foo)
{
switch(value)
{
case 0: {
return new AA(foo);
}
case 1: {
return new AB(foo);
}
case 2: {
return new AC(foo);
}
default: {
return new AA(foo);
}
}
}
In this example, I only have 3 types of children. But I could have let's say 30 of these, and the switch statement would become huge.
Is there any way to do the same thing using something else that a switch statement and that would be more generic? Like function pointers in C?
You can use a mapping of integer values to functional interfaces that create instances of the various sub-classes of A:
Map<Integer,Function<Object,A>> map = new HashMap<>();
map.put(0,f -> new AA(f));
map.put(1,f -> new AB(f));
...
Then use the mapping as follows:
public A getChild(int value, Object foo) {
return map.getOrDefault(value, f -> new AA(f)).apply(foo);
}
In java there is a similar concept of function pointers in C.
You can use the Java Reflection (but is not so efficient):
public A getChild(String className, Object foo)
{
Class c = Class.forName(className);
return (A) c.newInstance(Object foo);
}
And you can use a Map to keep associations between "int value" and "String className".
But this solution is not efficient!
Instead you can use a Map of Function as suggested by Eran.

Java design pattern to avoid duplication

I have the following classes
public class MyCustomFactory extends SomeOther3rdPartyFactory {
// Return our custom behaviour for the 'string' type
#Override
public StringType stringType() {
return new MyCustomStringType();
}
// Return our custom behaviour for the 'int' type
#Override
public IntType intType() {
return new MyCustomIntType();
}
// same for boolean, array, object etc
}
Now, for example, the custom type classes:
public class MyCustomStringType extends StringType {
#Override
public void enrichWithProperty(final SomePropertyObject prop) {
super.enrichWithProperty(prop);
if (prop.getSomeAttribute("attribute01")) {
this.doSomething();
this.doSomethingElse();
}
if (prop.getSomeAttribute("attribute02")) {
this.doSomethingYetAgain();
}
// other properties and actions
}
}
But each custom type class like the string one above might have exactly the same if (prop.getSomeAttribute("blah")) { // same thing; }
Suppose I was to add another attribute, is there a nice way I can avoid having to duplicate if statements in each custom type class that needs it? I can move each if statement to utility class but I still need to add the call to the method in the utility class. I think we can do better.
You can create Map<String, Consumer<MyCustomStringType>>, where the key is your attribute name and value is the method call.
public class MyCustomStringType extends StringType {
private final Map<String, Cosnumer<MyCustomStringType>> map = new HashMap<>();
{
map.put("attribute01", o -> {o.doSomething(); o.doSomethingElse();});
map.put("attribute02", MyCustomStringType::doSomethingYetAgain);
// other properties and actions
}
#Override
public void enrichWithProperty(final SomePropertyObject prop) {
super.enrichWithProperty(prop);
map.entrySet().stream()
.filter(entry -> prop.getSomeAttribute(entry.getKey()))
.forEach(entry -> entry.getValue().accept(MyCustomStringType.this));
}
}
Depending on how you initialise this class (and whether this map is always the same), you might be able to turn in into static final immutable map.
I would also recommend naming it better, but a lot here depends on your domain and what this map and loop actually do.

Which Java Design Pattern fits best for if-else statement including loop?

I have a use case with 7-8 if else. Sample use case:
String type;
List < Entity > entityList;
if (type.equals("A")) {
ClassA a = new ClassA();
a.performTask();
for (Entity e: entitylist) {
// do some task
}
}
else if (type.equals("B")) {
ClassB b = new ClassB();
b.performTask();
for (Entity e: entitylist) {
// do some different task
}
}
Which java design pattern fits best in this case as I want to eliminate this if else ladder?
If you really want to use a design pattern in this case I would suggest the Visitor Pattern. This is the one (as far as I know) which is best suited for this kind of "type-checking". You can find an good example here. But as alreday stated in the comments, I agree that a pattern would be to much overhead in this case.
Introduce an interface for all tasks and use a factory pattern. The factory can use a map internally. E.g.
public class TaskFactory {
private Map<String, Class<? extends Task>> taskTypeMap = new HashMap<String, Class<? extends Task>>();
public TaskFactory() {
taskTypeMap.put("A", ATask.class);
taskTypeMap.put("B", BTask.class);
}
public Task createTask(String type) {
Class<? extends Task> taskType = taskTypeMap.get(type);
if (taskType == null) {
throw new IllegalArgumentException("Task type " + type
+ " is not supported");
}
try {
return taskType.newInstance();
} catch (Exception e) {
throw new IllegalStateException(
"Unable to instantiate Task of type " + taskType, e);
}
}
}
Your client code will then change to
String type = ...;
List<Entity> entityList = ...;
TaskFactory taskFactory = new TaskFactory();
Task task = taskFactory.createTask(type);
task.performTask();
for (Entity e: entitylist) {
// do some task
}
A factory implementation could look like this:
public class WidgetFactory {
public static void main(String[] args) {
String type = "A";
List<Entity> entityList = new ArrayList<>();
Widget widget = WidgetFactory.createWidget(type);
widget.performTask();
for (Entity e : entityList) {
widget.performTaskOnEntity(e);
}
}
private static Widget createWidget(String type) {
switch (type) {
case "A":
return new ClassA();
case "B":
return new ClassB();
default:
throw new IllegalArgumentException("Unknown type: " + type);
}
}
private interface Widget {
void performTask();
void performTaskOnEntity(Entity entity);
}
private static class ClassA implements Widget {
public void performTask() { }
public void performTaskOnEntity(Entity entity) { }
}
private static class ClassB implements Widget {
public void performTask() { }
public void performTaskOnEntity(Entity entity) { }
}
private static class Entity {
}
}
You need the following patterns to make this design generic -
Factory Pattern - Make a BaseClass. Class A, B(and C...) should extend this BaseClass. BaseClass should have a single abstract method performTask() which should be implemented by Class A & Class B (and C...) to make them concrete implementations
Template Pattern - Lets define a base class for the template - BaseTemplateClass. Now, the reason why I am using a template pattern here is that you have 3 distinct steps in the flow here -
Step 1- Create a new instance of the BaseClass(we will use Factory defined in step 1 to do this). CreateInstance() will be the first concrete method in the TemplateBaseClass which will take in the string param identifier and call the factory. Since, this a fixed step we will keep CreateInstance() as a concrete method.
Step 2 - BaseClass's performTask() will be called. This will be abstract.
Step 3 - processEntityList() method will contain the for loop. This will also be a concrete method containing the call to the for loop - for (Entity e: entitylist){..}
Lastly, we need a method execute() in BaseTemplateClass which calls the 3 methods defined in Steps 1, 2 & 3.
An implementation of the BaseTemplateClass will have only the implementation of the abstract method performTask() as per its needs - in this case just invoking the A, B (or C...)'s performtask(). But this will be helpful if more needs to be done with A, B(or C...).
The client(in classical terms) just needs to call execute() method of an instance of suitable implementation of BaseTemplateClass and rest will happen as per the design above.

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.

Anonymous or real class definition when using visitor pattern?

When you use the Visitor pattern and you need to get a variable inside visitor method, how to you proceed ?
I see two approaches. The first one uses anonymous class :
// need a wrapper to get the result (which is just a String)
final StringBuild result = new StringBuilder();
final String concat = "Hello ";
myObject.accept(new MyVisitor() {
#Override
public void visit(ClassA o)
{
// this concatenation is expected here because I've simplified the example
// normally, the concat var is a complex object (like hashtable)
// used to create the result variable
// (I know that concatenation using StringBuilder is ugly, but this is an example !)
result.append(concat + "A");
}
#Override
public void visit(ClassB o)
{
result.append(concat + "B");
}
});
System.out.println(result.toString());
Pros & Cons :
Pros : you do not need to create a class file for this little behavior
Cons : I don't like the "final" keyword in this case : the anonymous class is less readable because it calls external variables and you need to use a wrapper to get the requested value (because with the keyword final, you can't reassign the variable)
Another way to do it is to do an external visitor class :
public class MyVisitor
{
private String result;
private String concat;
public MyVisitor(String concat)
{
this.concat = concat;
}
#Override
public void visit(ClassA o)
{
result = concat + "A";
}
#Override
public void visit(ClassB o)
{
result = concat + "B";
}
public String getResult()
{
return result;
}
}
MyVisitor visitor = new MyVisitor("Hello ");
myObject.accept(visitor);
System.out.println(visitor.getResult());
Pros & Cons :
Pros : all variables are defined in a clean scope, you don't need a wrapper to encapsulate the requested variable
Cons : need an external file, the getResult() method must be call after the accept method, this is quite ugly because you need to know the function call order to correctly use the visitor
You, what's your approach in this case ? Preferred method ? another idea ?
Well, both approaches are valid and imo, it really depends on whether you would like to reuse the code or not. By the way, your last 'Con' point is not totally valid since you do not need an 'external file' to declare a class. It might very well be an inner class...
That said, the way I use Visitors is like this:
public interface IVisitor<T extends Object> {
public T visit(ClassA element) throws VisitorException;
public T visit(ClassB element) throws VisitorException;
}
public interface IVisitable {
public <T extends Object> T accept(final IVisitor<T> visitor) throws VisitorException;
}
public class MyVisitor implements IVisitor<String> {
private String concat;
public MyVisitor(String concat) {
this.concat = concat;
}
public String visit(ClassA classA) throws VisitorException {
return this.concat + "A";
}
public String visit(ClassB classB) throws VisitorException {
return this.concat + "B";
}
}
public class ClassA implements IVisitable {
public <T> T accept(final IVisitor<T> visitor) throws VisitorException {
return visitor.visit(this);
}
}
public class ClassB implements IVisitable {
public <T> T accept(final IVisitor<T> visitor) throws VisitorException {
return visitor.visit(this);
}
}
// no return value needed?
public class MyOtherVisitor implements IVisitor<Void> {
public Void visit(ClassA classA) throws VisitorException {
return null;
}
public Void visit(ClassB classB) throws VisitorException {
return null;
}
}
That way, the visited objects are ignorant of what the visitor wants to do with them, yet they do return whatever the visitor wants to return. Your visitor can even 'fail' by throwing an exception.
I wrote the first version of this a few years ago and so far, it has worked for me in every case.
Disclaimer: I just hacked this together, quality (or even compilation) not guaranteed. But you get the idea... :)
I do not see an interface being implemented in your second example, but I believe it is there. I would add to your interface (or make a sub interface) that has a getResult() method on it.
That would help both example 1 and 2. You would not need a wrapper in 1, because you can define the getResult() method to return the result you want. In example 2, because getResult() is a part of your interface, there is no function that you 'need to know'.
My preference would be to create a new class, unless each variation of the class is only going to be used once. In which case I would inline it anonymously.
From the perspective of a cleaner design, the second approach is preferrable for the same exact reasons you've already stated.
In a normal TDD cycle I would start off with an anonymous class and refactored it out a bit later. However, if the visitor would only be needed in that one place and its complexity would match that of what you've provided in the example (i.e. not complex), I would have left it hanging and refactor to a separate class later if needed (e.g. another use case appeared, complexity of the visitor/surrounding class increased).
I would recommend using the second approach. Having the visitor in its full fledged class also serves the purpose of documentation and clean code. I do not agree with the cons that you have mentioned with the approach. Say you have an arraylist, and you don't add any element to it and do a get, surely you will get a null but that doesn't mean that it is necessarily wrong.
One of the points of the visitor pattern is to allow for multiple visitor types. If you create an anonymous class, you are kind of breaking the pattern.
You should change your accept method to be
public void accept(Visitor visitor) {
visitor.visit(this);
}
Since you pass this into the visitor, this being the object that is visited, the visitor can access the object's property according to the standard access rules.

Categories

Resources