In Moritz Haarmann's Blog I found an example of usage of Bonjour by Java. Here is the code taken from there:
public class ServiceAnnouncer implements IServiceAnnouncer, RegisterListener {
private DNSSDRegistration serviceRecord;
private boolean registered;
public boolean isRegistered(){
return registered;
}
public void registerService() {
try {
serviceRecord = DNSSD.register(0,0,null,"_killerapp._tcp", null,null,1234,null,this);
} catch (DNSSDException e) {
// error handling here
}
}
public void unregisterService(){
serviceRecord.stop();
registered = false;
}
public void serviceRegistered(DNSSDRegistration registration, int flags,String serviceName, String regType, String domain){
registered = true;
}
public void operationFailed(DNSSDService registration, int error){
// do error handling here if you want to.
}
}
I have a question about the "serviceRegistered" method. As far as I understand it is called during (or after) registration of the service (and it sets variable "registered" to be equal to "true"). But what is not clear to me is how exactly it is called. Because the service is registered by the method "registerService". This method, in its turn, calls "DNSSD.register". And, as far as I understand, the "DNSSD.register" will call the "serviceRegister" method of the "ServiceAnnouncer" class. But how "DNSSD.register" knows that it needs to call a method of the "ServiceAnnouncer" class? Can "DNSSD.register" know that it is called from a particular class (in this case "ServiceAnnouncer" class)?
The ServiceAnnouncer has passed itself as last argument of the DNSSD.register() method, which in turn is apparently expecting any instance of RegisterListener. This way the DNSSD can have a direct handle to the ServiceAnnouncer instance.
It seems that this class is a listener - namely RegisterListener. It has been registered as a listener in DNSSD by passing itself to the register(..) method.
For more information read about the Observer pattern.
Related
I am developing an application where I would like to use the observer pattern in the following way:
I have 2 classes:
public abstract class Storage<V>{
private Set<V> values;
private String filename;
protected Storage(String filename) throws ClassNotFoundException, IOException {
values = new HashSet<>();
this.filename = filename;
load();
}
...
public boolean add(V v) throws IllegalArgumentException {
if (values.contains(v))
throw new IllegalArgumentException("L'elemento è già presente");
return values.add(v);
}
...
}
Repository which is a class for saving a collection of Objects. below is a subclass that implements the singleton pattern (the others are practically the same, only the specified generic type changes)
public class AccountStorage extends Storage<Account>{
private static AccountStorage instance = null;
private AccountStorage(String filename) throws ClassNotFoundException, IOException {
super(filename);
}
public static synchronized AccountStorage getInstance() throws ClassNotFoundException, IOException {
if (instance == null) {
String savefile = "accounts.ob";
instance = new AccountStorage(savefile);
}
return instance;
}
after which I have a controller class (Controller for Spring MVC) which through a post request receives an Account in JSON format, deserializes it and adds it to the collection (Tremite the AccountStorage class) like this:
#PostMapping(value = "new/user", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public ResponseEntity<String> newAccount(#RequestBody Account a) {
synchronized (accounts) {
try {
accounts.add(a);
// accounts.save()
} catch (IllegalArgumentException e) {
return new ResponseEntity<String>(e.getMessage(), HttpStatus.BAD_REQUEST);
} catch (IOException e) {
return new ResponseEntity<String>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}
where accounts is: AccountStorage accounts = AccountStorage.getInstance();
I would like to make sure that, after each addition (or other methods that modify the collection) it is saved to file without calling the function affixed each time after the modification.
My idea is to use the Observer pattern. But I don't know which class must be an Observer and which Observable (assuming this approach is the correct solution).
The common practice for implementing the Observer pattern is to define an Observer interface (Listener) which will declare a general contact and each observer-implementation should provide an action which would be triggered whenever an event occurs.
A subject maintains a collection of observers (listeners), and exposes methods which allow to add and remove (subscribe/unsubscribe) an observer. Event-related behavior resides in the subject, and when a new event happens, every subscribed observer (i.e. each observer that is currently present in the collection) will be notified.
An event to which we are going to listen to is a case when a new Account gets added into an AccountStorage. And AccountStorage would be a subject. That implies that AccountStorage should hold a reference to a collection of observers, provide a functionality to subscribe/unsubscribe and override method add() of the Storage class in order to trigger all the observers when a new account will be added.
Why can't we add a collection of observers and all related functionality into the Storage class so that every implementation will inherit it? It's a valid question, the answer is that in such a scenario we can't be specific in regard to the nature of the event because we even don't know its type - method add(V) expects a mysterious V. Hence, the observer interface and its method would be faceless. It was the downside of the standard interfaces Observer and Observable that are deprecated since JDK version 9. Their names as well as the method-name update() tell nothing about an event that would be observed. It's only slightly better than define an interface MyInterface with a method myMethod() - no clue where you can use it and what actions should follow when myMethod() is fired.
It's a good practice when names of observers are descriptive, so that it's clear without looking at the code what they are meant to do. And it's not only related to the Observer pattern, it is a general practice which is called a self-documenting code.
Let's start by defining an observer interface, I'll call it listener just because AccountAddedListener sounds a bit smoothly, and it's quite common to use the terms listener and observer interchangeably.
public interface AccountAddedListener {
void onAccountAdded(Account account);
}
Now let's proceed with an implementation of the observer, let's say we need a notification manager:
public class NotificationManager implements AccountAddedListener {
#Override
public void onAccountAdded(Account account) {
// send a notification message
}
}
Now it's time to turn the AccountStorage into a subject. It should maintain a reference collection of observers, Set is a good choice because it'll not allow to add the same observer twice (which would be pointless) and is able to add and remove elements in a constant time.
Whenever a new account gets added, subject iterates over the collection of observers and invokes onAccountAdded() method on each of them.
We need to define a method to add a new observer, and it's also good practice to add another one to be able to unregister the observer when it's no longer needed.
public class AccountStorage extends Storage<Account> {
private Set<AccountAddedListener> listeners = new HashSet<>(); // collection of observers
#Override
public boolean add(Account account) throws IllegalArgumentException {
listeners.forEach(listener -> listener.onAccountAdded(account)); // notifying observers
return super.add(account);
}
public boolean registerAccountAddedListener(AccountAddedListener listener) {
return listeners.add(listener);
}
public boolean unregisterAccountAddedListener(AccountAddedListener listener) {
return listeners.remove(listener);
}
// all other functionality of the AccountStorage
}
We have few rules, which are Implemented as methods in Java. But sometimes we need to bypass the rules. So for each rule, we have a boolean Indicator to indicate whether to execute or not. What can be a good design to map the methods to boolean values in Database and execute methods based on the boolean values.
Below is sample template
1 Rule1 true
2 Rule2 false
3 Rule3 true
4 Rule4 true
So, now I need to execute method1(), method3() and method4() respectively.
One Simple way can be using If(rulee == true) executeMethod();
Second is using a Switch to execute the cases (method calls)
Note: We may need to execute the methods in different locations(methods). So please dont consider that all the methods will be called from a single method.
Can I make use of AOP by any chance?
You could define the basic interface as
public interface Rule {
boolean canExecute();
void execute();
}
and convert the methods into Rule interface implementations. The boolean value in the database would map to canExecute() return value.
This would be a good idea if methods are becoming complex, there's more than a few of them and the parent class is starting to look like a God Object.
Use Java 8 Stream api and Enums.
public class Main {
public enum Rule {
RULE1 {
#Override
public void doWork() {
}
},
RULE2 {
#Override
public void doWork() {
}
};
public abstract void doWork();
}
public static void main(String[] args) {
List<String> rules = new ArrayList<>();
rules.stream()
.map(Rule::valueOf)
.forEach(Rule::doWork);
}
}
You can just call all methods and do the validation part within the method implementation, e.g.:
void rule1(Object... args){
if (!applyRule1){
return;
}
...
}
With that approach, you can reduce cyclomatic complexity and prevent tools such as PMD from complaining.
Another approach is to store the method names as strings in the database. If your database supports arrays, that's particularly easy.
Then in Java you can set up an executor that accepts a String name and execute the respective rule:
import java.util.List;
import static java.util.Arrays.asList;
public class ByNameExecutor {
enum Rule {
Rule1 { #Override void rule() { System.out.println("Executed rule 1"); } },
Rule2 { #Override void rule() { System.out.println("Executed rule 2"); } },
Rule3 { #Override void rule() { System.out.println("Executed rule 3"); } },
Rule4 { #Override void rule() { System.out.println("Executed rule 4"); } },
;
abstract void rule();
}
public void execute(String ruleName) {
Rule.valueOf(ruleName).rule();
}
public void execute(List<String> ruleNames) {
ruleNames.stream().forEach(this::execute);
}
public static void main(String [] args) {
String [] methodList = { "Rule1", "Rule2", "Rule4" };
new ByNameExecutor().execute(asList(methodList));
}
}
An advantage of this approach is that you don't need to change the database schema to add a rule. Just start storing the new rule's string name. A disadvantage is that if you need to query on presence of or absence of a given rule, the database must support indexes over arrays.
Update: I replaced Consumer interface with Runnable in my original answer, because it aligns with example in the question better.
You can try to upgrade your Rule entity, here is an idea using Runnable interface:
class Rule {
private boolean isActive;
private Runnable runnable;
public Rule(boolean isActive, Runnable runnable) {
this.isActive = isActive;
this.runnable = runnable;
}
public void executeIfActive() {
if (isActive) {
runnable.run();
isActive = false;
}
}
}
Example of the use:
public class Demo {
public static void main(String[] args) {
Demo demo = new Demo();
List<Rule> rules = List.of(new Rule(true, demo::m1), new Rule(false, demo::m2));
rules.forEach(Rule::executeIfActive);
}
void m1() { ... }
void m2() { ... }
}
demo::m1 is a method reference that would invoke the method demo.m1(), and the same for m2.
If I understand the problem correctly then it should work. You can have a method like below and call it from anywhere.
Or these booleans can also be a rule and you can add multiple methods in one IF condition
void executeMethods(boolean m1, boolean m2, boolean m3, boolean m4){
if(m1) m1();
if(m2) m2();
if(m3) m3();
if(m4) m4();
}
executeMethods(true,false,false,true);
Instead of store Boolean you can store method names in this field accordingly. Then all you need to do would be invoke that method using reflection.
Table:
Id RULE_NAME METHOD_NAME
1 Rule1 method1
2 Rule2
3 Rule3 method3
4 Rule4 method4
The method can be invoked like this:
ResultSet srs = stmt.executeQuery("SELECT METHOD_NAME from table");
while (srs.next()) {
String methodName = srs.getString("METHOD_NAME");
if (!TextUtils.isEmpty(methodName)) {
Class<?> c = Class.forName("class name");
Method method = c.getDeclaredMethod(methodName, parameterTypes); // method name will be fetched from Database
method.invoke(objectToInvokeOn, params);
}
}
Reflection API > Invoking Methods
Lets solve this problem with a database driven approach, and Spring AOP.
You have several hundred rules, and do not wish to pollute the current code with boilerplate code like void method1() { if (!rule1) return; .. do method } or have to create additional interfaces which all rule based methods must implement.
Spring AOP provides a means to leave the current base in tact, and instead have methods intercepted (via a proxy) to determine if the method should run or not. You write the proxy code once, and the only ongoing requirement is to keep the database up to date with new rules.
Step 1: Build a database schema which maps method names to boolean values
method_name VARCHAR(100), is_rule_active tinyint(1);
There will be one row for each rule. The row will contain the method name (as it appears in the java code) and a boolean true=active, false=not active.
Step 2: Build an interface to the database (DAO)
You need a simple abstraction to the database. Something like:
public interface RuleSelectionInterface {
boolean isRuleActive(String methodName);
}
The implementation will be basic DAO code, which will query for the row with method_name equal to methodName. For simplicity, and to demonstrate, I used a Map instead:
#Repository
public class RuleSelectionImpl implements RuleSelectionInterface {
Map<String, Boolean> rules;
public RuleSelectionImpl() {
rules = new HashMap<>();
rules.put("rule1Method", true);
rules.put("rule2Method", false);
}
#Override
public boolean isRuleActive(String methodName) {
if (!rules.containsKey(methodName))
return false;
return rules.get(methodName);
}
}
Step 3: Create a Spring AOP aspect
An aspect is created to intercept method calls, and determine when the call should be executed.
To allow execution to be continued, or aborted, you use an #Around advice, which will be passed the execution point (by means of a ProceedingJoinPoint) from which you can either abort (the proxy method simply returns) or run the code by using the proceed method.
There is some choice here on which methods should be intercepted (this is done by defining pointcuts). This example will intercept methods with names starting with rule:
#Around("execution(* rule*(..))")
You could intercept all methods, or methods based on naming patterns, etc. For a detailed understanding of how to create pointcuts to intercept methods refer to Spring AOP
Here is the AOP code, which is called upon method interception, and which uses your database rule interface to look up if the rule is active for this method name:
#Aspect
#Component
public class RuleAspects {
#Autowired
private RuleSelectionInterface rulesSelectionService;
#Around("execution(* rule*(..))")
public void ruleChooser(ProceedingJoinPoint jp) throws Throwable
{
Signature sig = jp.getSignature();
System.out.println("Join point signature = "+sig);
String methodName = sig.getName();
if (rulesSelectionService.isRuleActive(methodName))
jp.proceed();
else
System.out.println("Method was aborted (rule is false)");
}
}
Sample usage:
I created a simple class with two methods (however this approach works regardless of how many classes/methods you have rule based methods for).
#Component
public class MethodsForRules {
public void rule1Method() {
System.out.println("Rule 1 method");
}
public void rule2Method() {
System.out.println("Rule 2 method");
}
}
You will have noticed in the Map that rule1Method is set to true, and rule2Method is set to false.
When the code tries to run rule1Method and rule2Method:
MethodsForRules r; // Is a Spring managed bean.
r.rule1Method();
r.rule2Method();
Produces the following output:
Join point signature = void com.stackoverflow.aoparound.demo.MethodsForRules.rule1Method()
Rule 1 method <- Here is the method running
Join point signature = void
com.stackoverflow.aoparound.demo.MethodsForRules.rule2Method()
Method was aborted (rule is false) <- Here the method is aborted
Summary:
This demonstration has shown how Spring AOP can be used, in combination with a rules based interface, to intercept methods (by using a proxy), examine the method name which was intercepted, lookup the active status for this method, and either run the method, or abort it.
I am fairly new to automated testing and I have been having some trouble with mocking a class with mockito. Basically what I am trying to do is make use of an interface that is being sent to a method, when this method (Request(Response)) is called I want mockito to intervene and call a method from the interface passing an object as a param (callback.OnSuccess(Obj)). Here is an example of what I mean, I will start off with my production code I have taken out everything that isnt needed:
ServerRequest class
public void Request(ResponseInterface callback){
//The contents of this class isnt really important as I do not wish to use any of it
//but in general this makes a request to the server and if the request is a success then
Object obj = ProcessResponse(Response);
callback.OnSuccess(obj);
//otherwise
Object obj = ProcessResponse(Response);
callback.OnError(obj);
}
ResponseInterface
public interface ResponseInterface(){
void OnSuccess(Object resp);
void OnError(Object resp);
}
MainActivity
public void MakeRequest(){
ServerRequest.Request(new ResponseInterface(){
#Override
public void OnSuccess(Object objResponse){
//do something to show user the request was successful depending on the current activity
}
#Override
public void OnError(String e){
//do something depending on the current activity
})
}
So far I have tried multiple methods, the best I could come up with is in the code below, but as I am sure you can tell from the post it did not work but I will leave it here as it might give somebody a better idea of what I am trying to do.
ServerRequest mockReq = mock(ServerRequest.class);
Mockito.doAnswer(new Answer<Void>() {
#Override
public Void answer(InvocationOnMock invocation) throws Throwable {
System.out.println("Running first time");
Object[] arguments = invocation.getArguments();
ResponseInterface inter = (ResponseInterface) arguments[2];
Object obj = "Already taken";
inter.OnSuccess(obj);
return null;
}
}).when(mockReq).InformationRequest(ArgumentMatchers.anyMap(),anyString(),ArgumentMatchers.<ServerInterface>any());
Any help on this matter would be greatly appreciated as I have no clue what I am doing.
In case anybody else is ever trying to achieve something similar I have figured out how to call the method in the interface sent through the mocked method.
So to start off I created setup method annotated with before (not necessarily needed you can place this just before your test in the same method). Then I began setting up everything needed to achieve my goals, here is the setup required.
//class to be mocked
#Mock
ServerRequest mockReq;
#Before
public void setup(){
//get the activity instance
Registration reg = mActivityRule.getActivity();
//make sure the actual method to be mocked does nothing, By default it should do nothing anyway but for some reason not for me
doNothing().when(mockReq).InformationRequest(ArgumentMatchers.anyMap(),anyString(),ArgumentMatchers.<ServerInterface>any());
//set up an argument catcher
captor = ArgumentCaptor.forClass(ServerInterface.class);
//inject the mock into the activity
reg.serverRequest = mockReq;
}
Next up in my test method the mocked method should be called when the submit button is clicked, in which case I verify the mocked method was actually called and capture the data sent to it, then I use the data in what ever manner I wish.
//click the button
onView(withId(R.id.SubmitBtn)).perform(scrollTo(), click());
//check to see if method was called then capture the interface
verify(mockReq).InformationRequest(ArgumentMatchers.anyMap(),anyString(),captor.capture());
//get the interface
ServerInterface serverInter = captor.getValue();
Object obj = "Already taken";
//make use of the interface
serverInter.OnSuccess(obj);
I have a question about asynchronous method calls in java, especially about the response value of the async method.
The situation is the following:
The async method I want to call is..
public void getSpeed(IResponseListener listener) {
....
}
The interface of the listener is...
interface IResponseListener {
public void response(ResponseEvent event);
}
This method is called when the async method has a response value
My problem now is that the class ResponseEvent has an attribute response that can be of any type (boolean,float,String...)and in the implementation of the interface IResponseListener I have to cast the value...
IResponseListener listener = new IResponseListener {
public void response(ResponseEvent event) {
float f = (float)event.response;
}
}
Is this a good solution to handle this? I think the bad thing is that the response listener HAS to know the type of the response!
Is there a better solution to handle asynchronous calls that want to give a response even if the response can be of any type?
I think a lot of these answers are starting to look like this->
public interface Function<Args, Value>
{
public Value call(Args args);
}
Your return type doesn't matter--if it can return multiple types, then the "multiple types" are a type...might I suggest a type of JSON considering what you're looking at?
The reality is you can't expect your handler to know the type in advance so you need to specify that. Whether this is with the return type or the class is up to you.
I could easily see doing a class hierarchy:
public class ResponseString implements Function<Args, String>;
public class ResponseNumber implements Function<Args, Number>;
...
public class ResponseType implements Function<Args, Type>;
or simply creating a type that has all the information you need. The long and short is that the method can DEFINE what it expects for the types and you have the ability to extend them. Keep in mind that response could also be a Function which could be executed. There's nothing wrong with knowing what to DO with something and not knowing what it is ->
Example->
//Admittedly I'd probably have a "Procedure or VoidFunction interface as well".
public yourMethod(Function<String args, Function<String,?> handler)
{
String hello = "hello";
Function<String,?> function = handler.call(hello);
function.call(hello);
}
I hope this helps. Sometimes there's no reason to go this far, and sometimes there is. You don't know the type--it seems like maybe you're hoping someone else will provide it and this can do that for you while remaining strict.
EDIT:
the example of have for this in one framework is:
Applcation.openDialog(Dialog dialog, Callable<Boolean> onClose);
This returns true of the dialog cleans up and closes and false if not. I don't really care what happens here, I do care that it tells me yes, close it, or no don't.
Use Java generics:
interface IResponseListener<T> {
public void response(T response);
}
Then, in an anonymous class:
IResponseListener listener = new IResponseListener<Float> {
public void response(Float response) {
float f = response;
}
}
I don't know whether this is correct, but if you are going to handle the return value differently, why not overload the response method with different type of objects that you would expect. Just a suggestion..
interface InterfaceName{
void response(float responseVal);
void response(boolean responseVal);
...
}
I would have done as #nico_ekito says...Or use your existing solution. It is a problem that you don't know the result type.
Anyway, you could do some adjustments and let the ResponseEvent class do the casting for you.
ResponseListener.java
interface IResponseListener {
void response(ResponseEvent event);
}
ResponseEvent.java
public class ResponseEvent {
private Object response;
#SuppressWarnings("unchecked")
public <T> T getResponse() {
return (T)response;
}
public <T> void setResponse(T response) {
this.response = response;
}
}
Usage:
IResponseListener listener = new IResponseListener() {
public void response(ResponseEvent event) {
float f = event.getResponse();
}
};
Please note that you will get a ClassCastException if your type is something other than what you expect it to be.
I have enum say ErrorCodes that
public enum ErrorCodes {
INVALID_LOGIN(100),
INVALID_PASSWORD(101),
SESSION_EXPIRED(102) ...;
private int errorCode;
private ErrorCodes(int error){
this.errorCode = error;
} //setter and getter and other codes
}
now I check my exception error codes with this error codes. I don't want to write if this do this, if this do this. How I can solve this problem (writing 10+ if blocks)
Is there any design patter to that situation ?
Thanks
Either you do it with a if-statement or a switch, or you just implement the logic in question into the ErrorCode somehow.
In an OO fashion it all depends on how you want the application or system react to the error code. Lets say you just want it to output somekind of dialog:
public doSomethingWithError() {
ErrorCodes e = getError();
// the source of error, or originator, returns the enum
switch(e) {
case ErrorCodes.INVALID_LOGIN:
prompt('Invalid Login');
case ErrorCodes.INVALID_PASSWORD:
prompt('Invalid password');
// and so on
}
}
We could instead create an ErrorHandler class that does this instead:
// We'll implement this using OO instead
public doSomethingWithError() {
ErrorHandler e = getError();
// the originator now returns an ErrorHandler object instead
e.handleMessage();
}
// We will need the following abstract class:
public abstract class ErrorHandler {
// Lets say we have a prompter class that prompts the message
private Prompter prompter = new Prompter();
public final void handleMessage() {
String message = this.getMessage();
prompter.prompt(message);
}
// This needs to be implemented in subclasses because
// handleMessage() method is using it.
public abstract String getMessage();
}
// And you'll have the following implementations, e.g.
// for invalid logins:
public final class InvalidLoginHandler() {
public final String getMessage() {
return "Invalid login";
}
}
// E.g. for invalid password:
public final class InvalidPasswordHandler() {
public final String getMessage() {
return "Invalid password";
}
}
The former solution is easy to implement, but becomes difficult to maintain as the code grows larger. The latter solution is more complex, (aka. Template Method pattern following the Open-Closed Principle) but enables you to add more methods into the ErrorHandler when you need it (such as restoring resources or whatever). You can also implement this with the Strategy pattern.
You won't get away completely with the conditional statements, but in the latter the conditional is pushed to the part of the code where the error is originated. That way you won't have double maintenance on conditional statements both at the originator and the error handling code.
EDIT:
See this answer by Michael Borgwardt and this answer by oksayt for how to implement methods on Java Enums if you want to do that instead.
Java enums are very powerful and allow per-instance method implementations:
public enum ErrorCode {
INVALID_LOGIN {
public void handleError() {
// do something
}
},
INVALID_PASSWORD {
public void handleError() {
// do something else
}
},
SESSION_EXPIRED {
public void handleError() {
// do something else again
}
};
public abstract void handleError();
}
Then you can simply call errorCode.handleError();. However, it is questionable whether an ErrorCode enum is really the right place for that logic.
As pointed out by Spoike, using polymorphism to pick the right error handling method is an option. This approach basically defers the 10+ if blocks to the JVM's virtual method lookup, by defining a class hierarchy.
But before going for a full-blown class hierarchy, also consider using enum methods. This option works well if what you plan to do in each case is fairly similar.
For example, if you want to return a different error message for each ErrorCode, you can simply do this:
// Note singular name for enum
public enum ErrorCode {
INVALID_LOGIN(100, "Your login is invalid"),
INVALID_PASSWORD(101, "Your password is invalid"),
SESSION_EXPIRED(102, "Your session has expired");
private final int code;
private final String
private ErrorCode(int code, String message){
this.code = code;
this.message = message;
}
public String getMessage() {
return message;
}
}
Then your error handling code becomes just:
ErrorCode errorCode = getErrorCode();
prompt(errorCode.getMessage());
One drawback of this approach is that if you want to add additional cases, you'll need to modify the enum itself, whereas with a class hierarchy you can add new cases without modifying existing code.
I believe the best you can do is implementing the strategy pattern. This way you won't have to change existing classes when adding new enums but will still be able to extend them. (Open-Closed-Principle).
Search for Strategy Pattern and Open Closed Principle.
You can create a map of error codes(Integer) against enum types
Edit
In this solution, once the map is prepared, you can look up an error code in the map and thus will not require if..else look ups.
E.g.
Map<Integer, ErrorCodes> errorMap = new HashMap<Integer, ErrorCodes>();
for (ErrorCodes error : ErrorCodes.values()) {
errorMap.put(error.getCode(), error);
}
Now when you want to check an error code coming from your aplpication, all you need to do is,
ErrorCodes error = errorMap.get(erro_code_from_application);
Thus removing the need for all the if..else.
You just need to set up the map in a way that adding error codes doesn't require changes in other code. Preparation of the map is one time activity and can be linked to a database, property file etc during the initialization of your application
In my opinion there is nothing wrong with ErrorCodes as enums and a switch statement to dispatch error handling. Enums and switch fit together really well.
However, maybe you find the following insteresting (kind of over-design), see an Example
or "Double dispatching" on Wikipedia.
Assumed requirements:
Error-handling should be encapsulated in an own class
Error-handling should be replacable
Type safety: Whenever an error is added, you are forced to add error handling at each error-handler implementation. It is not possible to "forget" an error in one (of maybe many) switch statments.
The code:
//Inteface for type-safe error handler
interface ErrorHandler {
void handleInvalidLoginError(InvalidLoginError error);
void handleInvalidPasswordError(InvalidLoginError error);
//One method must be added for each kind error. No chance to "forget" one.
}
//The error hierachy
public class AbstractError(Exception) {
private int code;
abstract public void handle(ErrorHandler);
}
public class InvalidLoginError(AbstractError) {
private String additionalStuff;
public void handle(ErrorHandler handler) {
handler.handleInvalidLoginError(this);
}
public String getAdditionalStuff();
}
public class InvalidPasswordError(AbstractError) {
private int code;
public void handle(ErrorHandler handler) {
handler.handleInvalidPasswordError(this);
}
}
//Test class
public class Test {
public void test() {
//Create an error handler instance.
ErrorHandler handler = new LoggingErrorHandler();
try {
doSomething();//throws AbstractError
}
catch (AbstractError e) {
e.handle(handler);
}
}
}