0

I'm implementing a strategy pattern for exceptions handling

 public class GlobalExceptionHandler {

    private interface Strategy<T extends Exception> {
        ErrorResponse extract(T e);
    }

    private static class ResponseStatusStrategy implements Strategy<ResponseStatusException> {
        @Override
        public ErrorResponse extract(ResponseStatusException e) {
            return ErrorResponse.builder()
                    .status(e.getStatus())
                    .message(e.getReason())
                    .description(e.getReason())
                    .build();
        }
    }

    private static class IllegalStateStrategy implements Strategy<IllegalStateException> {
        @Override
        public ErrorResponse extract(IllegalStateException e) {
            return ErrorResponse.builder()
                    .status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .message(e.getMessage())
                    .description("")
                    .build();
        }
    }
    ....

I call this API like this:

Exception ex = ....; // function param
if (ex instanceof ResponseStatusException) {
    errorResponse = new ResponseStatusStrategy().extract((ResponseStatusException) ex);
} else if (ex instanceof IllegalStateException) {
    errorResponse = new IllegalStateStrategy().extract((IllegalStateException) ex);
} else {
    errorResponse = new EmptyStrategy().extract(ex);
}

Is there a more efficient and beautiful way to implement this? Idea gets me hint that I even didn't use interface method: "method extract(T e) is never used".

It would be great to have API like this:

    Strategy<???> strategy;
    if (ex instanceof ResponseStatusException) {
        strategy = new ResponseStatusStrategy();
    } else if (ex instanceof IllegalStateException) {
        strategy = new IllegalStateStrategy();
    } else {
        strategy = new EmptyStrategy();
    }
    errorResponse = strategy.extract(ex);
Tipok
  • 675
  • 8
  • 26
  • 3
    You don't seem to have a reason to use the strategy pattern at all. I suggest you don't. `if (ex instance of IllegalStateException) {errorResponse = ....}` works just fine, and you don't have to make a whole bunch of classes for no good reason. – Matt Timmermans Oct 30 '19 at 03:37
  • @MattTimmermans Let's pretend that I need it. I want to know how can I resolve such situations with generics in future. – Tipok Oct 30 '19 at 03:39
  • 1
    In situations where the strategy pattern is appropriate, you don't have this problem. – Matt Timmermans Oct 30 '19 at 03:41
  • @MattTimmermans is it because of interface is not generic in this pattern? – Tipok Oct 30 '19 at 03:49
  • 1
    Yes, with the strategy pattern, the type of things you *have* are invariant, and what you do with them are variable or configured. Sometimes the strategy interface is generic when the types are unbounded, and then the strategies are typically stored in a `Map, Strategy>>`. The key point, however, is that the strategies are variable/configured, and then the implementation follows from how you allow configuration to be defined. – Matt Timmermans Oct 30 '19 at 04:05

1 Answers1

2

You are trying to solve an object creational problem. You want a particular Strategy class object based on the StatusException class. Create a new class with a factory pattern to return you the correct object. Here is some dummy code inspired from your code.

private interface Factory {
    Strategy buildStrategy(Exception e);
}
private static class FactoryImpl implements Factory {
    public Strategy buildStrategy(Exception e) {
        if (e instanceof IOException) {
            return new Strategy1();
        } else {
            return new EmptyStrategy();
        }
    }
}

private interface Strategy<T extends Exception> {
    String extract();
}
private static class Strategy1 implements Strategy<IOException> {
    @Override public String extract() {
        return "Strategy1";
    }
}
private static class EmptyStrategy implements Strategy<NamingException> {
    @Override public String extract() {
        return "EmptyStrategy";
    }
}

public static void main(String[] args) {
    var f = new FactoryImpl();
    System.out.println(f.buildStrategy(new IOException()).extract());
    System.out.println(f.buildStrategy(new NamingException()).extract());
}
Jay Rajput
  • 1,813
  • 17
  • 23
  • [Don't use raw type](https://stackoverflow.com/questions/2770321/what-is-a-raw-type-and-why-shouldnt-we-use-it) `Strategy`. Replace `Strategy buildStrategy(Exception e);` with ` Strategy super E> buildStrategy(E e);`. – IlyaMuravjov Oct 30 '19 at 09:55
  • Would you provide how you want the code to look like? I am still looking at how to update the code.. – Jay Rajput Oct 31 '19 at 16:20