I have a large method that looks something like this
List<Hotel> findAvailHotels(Provider provider, Method method, List<String> codes) {
switch (provider) {
case PROVIDER_1:
//TODO Do common things to provider 1
switch (method) {
case HOTEL_CODE:
break;
case DESTINATION_CODE:
break;
case GEO:
break;
}
break;
case PROVIDER_2:
switch (method) {
case HOTEL_CODE:
break;
case DESTINATION_CODE:
break;
case GEO:
break;
}
break;
}
So each time I need to add a provider I'll need to add a case to that provider and then repeat the method switch for this new provider.
I got a suggestion from a fellow that should be split into methods for each method so for example instead of the above, it'll be
List<Hotel> findAvailHotelsByHotelCode(Provider provider, List<String> codes) {
switch (provider) {
case PROVIDER_1:
//TODO Do common things to provider 1
break;
case PROVIDER_2:
break;
}
List<Hotel> findAvailHotelsByDestinationCode(Provider provider, List<String> codes) {
switch (provider) {
case PROVIDER_1:
//TODO Do common things to provider 1
break;
case PROVIDER_2:
break;
}
List<Hotel> findAvailHotelsByGeo(Provider provider, List<String> codes) {
switch (provider) {
case PROVIDER_1:
//TODO Do common things to provider 1
break;
case PROVIDER_2:
break;
}
Personal thoughts: Maybe splitting into multiple methods makes it more cleaner but if I need to do common stuff to PROVIDER_1 (despite the method) then this common thing will need to be repeated/duplicated in each method (as indicated by the //TODOs in the above code) which kinda means more lines of code but that's a bit irrelevant maybe.
I'd like to hear some thoughts about this, which would you consider more readable and more clean? Any better alternatives?
edit: To give more context, I work with hotel providers.. most providers have 3 common methods of search (hotel_code, destination_code, geo).. from outside this method I can do a hotel_code search for all providers (by looping over the Provider enum and calling the method for each provider with hotel_code enum param).. or I can do it to a specific provider.
Your Question is still a little too abstract to suggest a "best" solution, but Timothy is right so far - in either case you can use polimorphism.
I suggest Strategy pattern because you define the broad structure by using an interface and create an a dedicated class for every single algorithm (provider in your case).
This has at least two advantages:
You have an easy to oversee List of algorithms in the form of classes.
You can replace the outer switch by a loop through your strategy objects.
Hmm - since you asked for it - here is some example code (a little large though ...)
import java.util.ArrayList;
import java.util.List;
public class HotelStuff {
private static class Hotel{/* does whatever ...*/}
private enum SearchMethod{
HOTELCODE,
DESTINATIONCODE,
GEOCODE
}
private interface Providable{
List<Hotel> findAvailHotels(SearchMethod method, List<String> codes);
}
private static class Provider1 implements Providable{
#Override
public List<Hotel> findAvailHotels(SearchMethod method, List<String> codes) {
// TODO create the list ...
return null;
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
List<Providable> providers = new ArrayList<Providable>();
providers.add(new Provider1());
// providers.add(new Provider2 .. and so on
List<String> codes = Arrays.asList("123","456");
SearchMethod method = SearchMethod.GEOCODE;
List<Hotel> availableHotels = findAvailHotels(providers, method, codes);
}
public static List<Hotel> findAvailHotels(List<Providable> providers, SearchMethod method, List<String> codes) {
List<Hotel> result = new ArrayList<Hotel>();
List<Hotel> partResult;
for(Providable provider: providers) {
partResult = provider.findAvailHotels(method, codes);
result.addAll(partResult);
}
return result;
}
}
Of course you should implement the classes in seperate files - i just put them into one file to shorten it.
Unless your switch statement is in a factory you should better use polymorphism.
You should look into both the visitor pattern and double dispatch.
The Gang of Four defines the Visitor as:
Represent an operation to be performed on elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.
In your case Provider is the object and Method is the operation.
Double dispatch is useful in situations where the choice of computation depends on the runtime types of its arguments. In your case: you want to do something based on the type of Provider and Method.
Related
I need to refactor a code that uses multiple case statements based on the queryString value it receives. Everytime a new query is added , we had to add a new case statement. Can we try to simplify it and make it more generic so that we dont have to keep on adding new case statements? Below is the code snippet
switch (queryRequestRecevied) {
case query1:
reply = processQuery1();
break;
case query2:
reply = processQuery2();
break;
case query3:
reply = processQuery3();
break;
case query4:
reply = processQuery4();
break;
case query5:
reply = processQuery5();
break;
case query6:
reply = processQuery6();
break;
default:
reply = processInvalidQuery();
break;
}
The name for the operation you're looking for is Replace Conditional with Polymorphism: Instead of having switch or if statements, use a common interface for your cases and invoke that. I'm presuming here that your query returns some value and using Supplier; if not, use another functional interface or create your own.
Map<String, Supplier<QueryResult>> queryProcessors = new HashMap<>();
...
// in a constructor or similar place
queryProcessors.put(query1, this::processQuery1);
queryProcessors.put(query2, this::processQuery2);
// in your handler method
var result = queryProcessors.getOrDefault(query, this::processInvalidQuery).get();
To decouple even further, you can do this:
// declare some Spring beans implementing this interface
interface QueryProcessor {
String getQuery();
QueryResult processQuery();
}
// in your service class
Map<String, QueryProcessor> queryProcessors;
#Autowired //(not necessary for a single constructor)
MyService(Collection<QueryProcessor> queryProcessors) {
this.queryProcessors = queryProcessors.stream()
.collect(toMap(QueryProcessor::getQuery, identity()));
}
You don't give enough code to see what could be factorized / more generic.
But at least instead of testing your input query you could declare 1 endpoint per query in your #Controller then no need to Switch / case testing.
Using blocks of code with switch or if is a common thing when checking for events. It can be clean code when made simple, but still seems to have more lines than needed, and could be simplified using lambdas.
Block with if:
if(action == ACTION_1){
doAction1();
} else if(action == ACTION_2){
doAction2();
} else {
doDefaultAction();
}
Block with switch:
switch(action){
case ACTION_1:
doAction1();
break;
case ACTION_2:
doAction2();
break;
default:
doDefaultAction();
}
Block with lambdas using the utility class With below:
with(action)
.when(ACTION_1, this::doAction1)
.when(ACTION_2, this::doAction2)
.byDefault(this::doDefaultAction)
Using lambdas has less code, but the question is: is it easier to read than the others? Easier to maintain? Regarding performance lambdas is the worst, but for cases where performance is not important the lambdas version is shorter than the switch/if blocks.
So, how do you see it? Maybe there is a Kotlin way shorter than this, I try to focus on java only, I love Kotlin but the compilation is still too slow for my projects.
A similar utility class could be used when the block must return a specific value.
FYI, the class for the lambdas is here, I didn't check for errors, just made it quickly for this example:
public class With<T> {
private final T id;
private boolean actionFound;
private With(T id) {
this.id = id;
}
public static <T> With<T> with(T id) {
return new With<>(id);
}
public With<T> when(T expectedId, Action action) {
if (!actionFound && id == expectedId) {
actionFound = true;
action.execute();
}
return this;
}
public void byDefault(Action action) {
if (!actionFound) {
action.execute();
}
}
#FunctionalInterface
interface Action {
void execute();
}
}
As a couple has said, replacing switch with compounded methods is less efficient. Depending on your use-case, it might even be worth it to use your implementation.
Funnily enough, Oracle is actually planning to implement lambdas within switch statements, as seen in this recent JEP.
Example:
String formatted = switch (s) {
case null -> "(null)";
case "" -> "(empty)";
default -> s;
}
The switch is more flexible in that you can call functions with varying numbers of arguments, or call more than one function. You can also more easily denote when two cases lead to the same action. The fact that it's faster is just a bonus.
So in that sense I'm not sure what your With class is really adding.
However, switch has a limited number of types that it can work with. Perhaps your With class would prove to be more useful if you were to pass it predicates rather than performing simple reference equality, for example:
public With<T> when(Predicate<T> expected, Action action) {
if (!actionFound && expected.test(id)) {
actionFound = true;
action.execute();
}
return this;
}
Sample usage:
final String test = "test";
with(test)
.when(String::isEmpty, this::doAction1)
.when(s -> s.length() == 3, this::doAction2)
.byDefault(this::doDefaultAction);
replace switch with lambdas. Worth it?
No.
Because in an OO language the replacemenst for a switch or an if/else cascade is polymorphism, not "fluent API".
One option to do this is to declare static final Map<T, Action> EXPECTED_ID_TO_ACTION. Then you just can EXPECTED_ID_TO_ACTION.getOrDefault(actionId, DEFAULT_ACTION).execute(), turning ugly switch or multiple ifs into one-liner.
In most radio devices, we can configure the wave which we want to explore and listen to stations using the demodulation mode compatible with this type.
There are at least two types AM and FM. We can model the radio device in this case as the following:
class RadioDevice {
void demodulate (String m) {
if(m.equals("FM")
/* FM modelation */
else if(m.equals("AM")
/* AM modelation */
}
}
How can I apply the strategy pattern in this case?
Why don't you use polymorphism ?
Make an interface:
interface Radio {
void modulate();
}
And than implement 2 classes:
FMRadio implements Radio{
public void demodule(){
//FM modulation
}
}
AMRadio implements Radio{
public void demodule(){
//AM modulation
}
}
And than, in your main, you could go:
Radio myRadio = new FMRadio();
myRadio.demodule();
If you can have an interface that covers the contract for both AM and FM demodulation, you could use the Strategy pattern:
Demodulator d; // interface Demodulator { byte[] demodulate(); }
switch(m) {
case "AM":
d = new AMDemodulator();
break;
case "FM"
d = new FMDemodulator();
break;
default:
throw new IllegalArgumentException("Unsupported type '"+ m + "'"); // you could use an Enum instead of a String
}
d.demodulate(waves);
This allows you to switch the Demodulator part on the fly while keeping the rest of the program logic in common (no duplication).
Check this repo (not mine) for design patterns and examples: https://github.com/iluwatar/java-design-patterns
To make it a proper Strategy pattern, I would add using a Context class to the previous answer of #Ladislav_M, that will wrap & encapsulate executing a particular strategy and give more flexibility to the code:
class Context {
private Radio radio;
public Context(Radio radio) {
this.radio = radio;
}
public Object runStrategy() {
radio.demodulate();
// do any other stuff you want
return ...
}
}
The execution in main would become more convenient:
Context context = new Context(new FmRadio());
Object result = context.runStrategy();
Or you can inline the above:
Object result = (new Context(new FmRadio())).runStrategy();
Of course, you can choose the implementation of Radio in a switch block and just pass it as a variable to the Context's constructor.
This is not a good use case for Strategy design pattern, its simple inheritance case. Strategy is used where the state of the object does not change but different algorithms apply at different times. e.g. Paypackage computation for different roles of employees (e.g. Temporary, Permanent etc.). Important point here is Temporary employee can become Permanent one day.
In the above case AM will never become FM in its life time. hence Strategy is not right pattern for it. These are (probably) different classes with common behavior (if present) can be shifted to base class. If they show a common contract with clients then even interface will do the task.
I am making a multiplayer game which makes heavy use of a serialisable Event class to send messages over a network. I want to be able to reconstruct the appropriate subclass of Event based on a constant.
So far I have opted for the following solution:
public class EventFactory {
public static Event getEvent(int eventId, ByteBuffer buf) {
switch (eventId){
case Event.ID_A:
return EventA.deserialise(buf);
case Event.ID_B:
return EventB.deserialise(buf);
case Event.ID_C:
return EventC.deserialise(buf);
default:
// Unknown Event ID
return null;
}
}
}
However, this strikes me as being very verbose and involves adding a new 'case' statement every time I create a new Event type.
I am aware of 2 other ways of accomplishing this, but neither seems better*:
Create a mapping of constants -> Event subclasses, and use clazz.newInstance() to instantiate them (using an empty constructor), followed by clazz.initialiase(buf) to supply the necessary parameters.
Create a mapping of constants -> Event subclasses, and use reflection to find and call the right method in the appropriate class.
Is there a better approach than the one I am using? Am I perhaps unwise to disregard the alternatives mentioned above?
*NOTE: in this case better means simpler / cleaner but without compromising too much on speed.
You can just use a HashMap<Integer,Event> to get the correct Event for the eventID. Adding or removing events is going to be easy, and as the code grows this is easy to maintain when compared to switch case solution and speed wise also this should be faster than switch case solution.
static
{
HashMap<Integer,Event> eventHandlerMap = new HashMap<>();
eventHandlerMap.put(eventId_A, new EventHandlerA());
eventHandlerMap.put(eventId_B, new EventHandlerB());
............
}
Instead of your switch statement Now you can just use :
Event event = eventHandlerMap.get(eventId);
if(event!=null){
event.deserialise(buf);
}
If you're not afraid of reflection, you could use:
private static final Map<Integer, Method> EVENTID_METHOD_MAP = new LinkedHashMap<>();
static {
try {
for (Field field : Event.class.getFields())
if (field.getName().startsWith("ID_")) {
String classSuffix = field.getName().substring(3);
Class<?> cls = Class.forName("Event" + classSuffix);
Method method = cls.getMethod("deserialize", ByteBuffer.class);
EVENTID_METHOD_MAP.put(field.getInt(null), method);
}
} catch (IllegalAccessException|ClassNotFoundException|NoSuchMethodException e) {
throw new ExceptionInInitializerError(e);
}
}
public static Event getEvent(int eventId, ByteBuffer buf)
throws InvocationTargetException, IllegalAccessException {
return (Event) EVENTID_METHOD_MAP.get(eventId).invoke(null, buf);
}
This solution requires that int ID_N always maps to class EventN, where N can be any String where all characters return true for the method java.lang.Character.isJavaIdentifierPart(c). Also, class EventN must define a static method called deserialize with one ByteBuffer argument that returns an Event.
You could also check if field is static before trying to get its field value. I just forget how to do that at the moment.
I have this switch statement which is executed after the user is shown a list of actions to take and clicks one of them. What we switch on is the action ID
switch (actionId) {
case 0:
openEditProductScreen();
break;
case 1:
startDeleteProductOperation();
break;
case 2:
//nothing
break;
case 3:
openAddProductScreen();
break;
}
I have read some articles on replacing switches with polymorphism but they relate to another type of problem - doing the same thing in different ways (the way you pay different types of employees), but what do I do when I want to trigger a completely different set of actions?
Thinking about it, do I really need to eliminate THIS particular kind of switch statement? I mean, it's readable and logical. What would the benefits be if I eliminated it somehow?
EDIT:
Is this what you meant?
private Map<Integer, ProductRelatedAction> productRelatedActions = new HashMap<Integer, ProductRelatedAction>();
private void mapActionsToIds() {
productRelatedActions.put(0, new EditProductAction());
productRelatedActions.put(1, new DeleteProductAction());
// remainder omitted
}
private abstract class ProductRelatedAction{
abstract void execute();
}
private class EditProductAction extends ProductRelatedAction{
#Override
void execute() {
openEditProductScreen();
}
}
private class DeleteProductAction extends ProductRelatedAction{
#Override
void execute() {
startDeleteProductOperation();
}
}
Add an abstract method execute() in the Action class, create 4 subclasses of Action, overriding execute(). Make the first one execute openEditProductScreen(), the second one execute startDeleteProductOperation(), etc.
Then create one instance of these 4 classes and make the user choose one of those 4 instances.
When the user has chosen the action, call selectedAction.execute().
Should you replace this kind of switch by polymorphism? In my opinion: yes. When you'll have to add another action, there is no way you'll be able to forget to implement the execute() method in the new subclass: your code won't compile without it. On the other hand, Forgetting to add a case in your switch statement is extremaly easy to do. And I'm not even mentioning the fall-through problem of switch statements.