How can I override a method of an anonymous generic class?

时间:2015-09-01 22:00:37

标签: java generics design-patterns gwt anonymous-types

I am working on GWT project with JDK7. It has two entryPoints (two clients) that are located in separate packages of the project. Clients share some code that is located in /common package, which is universal and accessible to both by having the following line in their respective xml-build files:

    <source path='ui/common' />

Both clients have their own specific implementations of the Callback class which serves their running environments and performs various actions in case of failure or success. I have the following abstract class that implements AsyncCallback interface and then gets extended by its respective client.

public abstract class AbstractCallback<T> implements AsyncCallback<T> {
    public void handleSuccess( T result ) {}
    ...
}

Here are the client's classes:

public class Client1Callback<T> extends AbstractCallback<T> {...}

and

public class Client2Callback<T> extends AbstractCallback<T> {...}

In the common package, that also contains these callback classes, I am working on implementing the service layer that serves both clients. Clients use the same back-end services, just handle the results differently. Based on the type of the client I want to build a corresponding instance of AbstractCallback child without duplicating anonymous class creation for each call. I am going to have many declarations that will look like the following:

   AsyncCallback<MyVO> nextCallback = isClient1 ?
                    new Client1Callback<MyVO>("ABC") {
                        public void handleSuccess(MyVO result) {
                            doThatSameAction(result);
                        }
                    }
                    :
                    new Client2Callback<MyVO>("DEF") {
                        public void handleSuccess(MyVO result) {
                            doThatSameAction(result);
                        }
                    };

That will result in a very verbose code.

The intent (in pseudo-code) is to have the below instead:

AsyncCallback<MyVO> nextCallback = new CallbackTypeResolver.ACallback<MyVO>(clientType, "ABC"){
            public void handleSuccess(MyVO result) {
                doThatSameAction(result);
            }
        };

I was playing with the factory pattern to get the right child instance, but quickly realized that I am not able to override handleSuccess() method after the instance is created.

I think the solution may come from one of the two sources:

  1. Different GWT way of dealing with custom Callback implementations, lets call it alternative existent solution.
  2. Java generics/types juggling magic

I can miss something obvious, and would appreciate any advice. I've read some articles here and on Oracle about types erasure for generics, so I understand that my question may have no direct answer.

1 个答案:

答案 0 :(得分:1)

Refactor out the handleSuccess behavior into its own class.

The handleSuccess behavior is a separate concern from what else is going on in the AsyncCallback classes; therefore, separate it out into a more useful form. See Why should I prefer composition over inheritance?

Essentially, by doing this refactoring, you are transforming an overridden method into injected behavior that you have more control over. Specifically, you would have instead:

public interface SuccessHandler<T> {
    public void handleSuccess(T result);
}

Your callback would look something like this:

public abstract class AbstractCallback<T> implements AsyncCallback<T> {
    private final SuccessHandler<T> handler; // Inject this in the constructor

    // etc.

    // not abstract anymore
    public void handleSuccess( T result ) {
        handler.handleSuccess(result);
    }
}

Then your pseudocode callback creation statement would be something like:

AsyncCallback<MyVO> nextCallback = new CallbackTypeResolver.ACallback<MyVO>(
            clientType, 
            "ABC", 
            new SuccessHandler<MyVO>() {
                public void handleSuccess(MyVO result) {
                    doThatSameMethod(result);
                }
            });

The implementations of SuccessHandler don't have to be anonymous, they can be top level classes or even inner classes based on your needs. There's a lot more power you can do once you're using this injection based framework, including creating these handlers with automatically injected dependencies using Gin and Guice Providers. (Gin is a project that integrates Guice, a dependency injection framework, with GWT).