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.
Related
This question already has answers here:
How to avoid a lot of if else conditions
(8 answers)
Closed 4 years ago.
In my program, I need to check if a variable equals 1, 2 or 3 and depending on the result, perform a different method:
if (phase.equals("1")) {
PhaseOne.performPhase(inputParser.getSource(), inputParser.getTarget());
} else if (phase.equals("2")) {
PhaseTwo.performPhase(inputParser.getSource(), inputParser.getTarget());
} else {
PhaseThree.performPhase(inputParser.getSource(), inputParser.getTarget());
}
This code is so simple and basic but I really don't like it. Of course I could use switch conditions but it would, in my humble opinion, just display the same basic function in a different way.
My question is: is there a way to implement the function in an elegant and expandable way?
FYI, I already red this post but I did not find an answer which fits to my question.
In my opinion, the accepted answer on your linked question fits you very well. Store references to the functions in the map:
Map<String,BiConsumer<T,U>> map = new HashMap<>();
map.put("1",PhaseOne::performPhase);
map.put("2",PhaseTwo::performPhase);
map.put("3",PhaseThree::performPhase);
map.get(phase).accept(inputParser.getSource(), inputParser.getTarget());
Replace T and U by the types of inputParser.getSource() and inputParser.getTarget().
With this approach, the Phase… classes don't need a common superclass or interface.
If your PhaseOne/PhaseTwo/PhaseThree classes all implement the same interface (let's say Phase), and the method performPhase is defined on the interface you could do the following:
final Phase targetPhase;
switch(phase) {
case "1": targetPhase = myInstanceOfPhaseOne; break;
case "2": targetPhase = myInstanceOfPhaseTwo; break;
case "3": targetPhase = myInstanceOfPhaseThree; break;
default: throw new IllegalStateException("Unrecognised phase "+phase);
}
targetPhase.performPhase(inputParser.getSource(), inputParser.getTarget()));
Another option is to create a Class for each Phase and an IPhase Interface for them to implement.
Create a List<IPhase> with all your different Phase instances.
Run a loop and if the id matches, execute the overwritten method.
public interface IPhase {
public void performPhase();
public String getId();
}
for (IPhase phase : phasesList){
if (phase.equals(phase.getId())){
phase.performPhase();
// either break or continue the loop
}
}
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 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.
Im learning java and i have come across a function calc (have changed few objects and removed few lines), however i couldnt understand below code...
I understand this follows builder pattern
Questions:
i have never seen this before and due to poor search i havent got much help from googling... can we do return new Object and a function below that...
How this can be explained in simple terms
case 1 with no coding and default below that; does it mean 1 is most of the time default
Here is my code:
public calc(int value)
{
switch (value) {
case 0:
return new validator<objValidator>() {
#Override
public Boolean evaluate() {
//some business logic to return true/false
return true;
}
};
case 1:
default:
return new validator<objValidator>() {
#Override
public Boolean evaluate() {
//some business logic to return true/false
return true;
}
};
}
}
What you see here is called an anonymous inner class. Searching for that term should bring up some useful results.
Basically validator<objValidator> is an interface and you create an implementation of it in-place.
These are called as Anonymous Classes.
See this link.
Question 1: yes you can
think about it like defining a new Anonymous class inside it
for more info about Anonymous classes
please see this link
enter link description here
Question 2:
case 1: means no action done if the value is 1
case default: means if the value not = 1 then the function below will be executed
for more info about switch case statement
please point to this link
I want to make a simple interative shell based on the console where I can write commands like login, help, et cetera.
I first thought of using Enums, but then I didn't know how to implement them neatly without a load of if-else statements, so I decided to go with an array-approach and came up with this:
public class Parser {
private static String[] opts = new String[] {"opt0", "opt1", "opt2", "opt3" ... }
public void parse(String text) {
for(int i = 0; i < opts.length; i++) {
if(text.matches(opts[i]) {
switch(i) {
case 0:
// Do something
case 1:
// Do something-something
case 2:
// Do something else
}
return;
}
}
}
}
But I ended up seeing that this was probably the most rudimentary way of doing something like this, and that there would be problems if I wanted to change the order of the options. How could I make a simpler parser? This way it would work, but it would also have said problems. The use of the program is purely educational, not intended for any serious thing.
A simple approach is to have a HashMap with the key equal to the command text and the value is an instance of class that handle this command. Assuming that the command handler class does not take arguments (but you can easily extend this) you can just use a Runnable instance.
Example code:
Runnable helpHandler = new Runnable() {
public void run(){
// handle the command
}
}
// Define all your command handlers
HashMap<String, Runnable> commandsMap = new HashMap<>(); // Java 7 syntax
commandsMap.put("help",helpHandler);
// Add all your command handlers instances
String cmd; // read the user input
Runnable handler;
if((handler = commandsMap.get(cmd)) != null) {
handler.run();
}
You can easily extend this approach to accept argument by implementing your own interface and subclass it. It is good to use variable arguments if you know the data type e.g. void execute(String ... args)
One solution that comes to mind is actually using Design patterns. You could use the input from the user, as the discriminator for a Factory class.
This factory class will generate an object, with an "execute" method, based on the input. This is called a Command object.
Then you can simply call the method of the object returned from the factory.
No need for a switch statement. If the object is null, then you know the user entered an invalid option, and it abstracts the decision logic away from your input parser.
Hopefully this will help :)