I like that you've taken the idea of my PresenterProxy (http://
groups.google.com/group/google-web-toolkit/browse_thread/thread/
6ec343860253c621/20ab002804a6ee6e) and expanded it to support most any
class imaginable.
However, a side effect of this solution is that dependent classes
(your ButtonPanel, in this example) must now be updated to rely on the
*Shim class instead of the original class used before the shim.
One of the tenets of dependency injection is that you should be
injecting dependencies according to interface, not implementation (see
Martin Fowler's explanation: http://www.martinfowler.com/articles/injection.html#InterfaceInjection).
So your dependent classes shouldn't have to change when your
implementation changes, nor should they care what type of
implementation they receive.
So in that regard, while using the shim may provide a nice way to
abstract some boilerplate, it does break your existing API contracts
and it requires that you define new *Shim contracts that are likely to
duplicate existing API contracts.
If the underlying implementation in the shim is to be created and
delegated to asynchronously, then it is true that each shimmed method
must return void (similar to the RPC async interfaces), and that
imposes some limitation on what we can readily abstract.
But perhaps you are on to something with the use of deferred binding.
However, maybe what we should be looking at doing with the deferred
binding is utilizing a generator that can (at compile time) generate a
unique subclass of the original class capable of performing the
asynchronous grunt work automatically. Perhaps if I have some time I
can toy with that idea...
However, a side effect of this solution is that dependent classes
(your ButtonPanel, in this example) must now be updated to rely on the
*Shim class instead of the original class used before the shim.
One of the tenets of dependency injection is that you should be
injecting dependencies according to interface, not implementation (see
Martin Fowler's explanation: http://www.martinfowler.com/articles/injection.html#InterfaceInjection).
So your dependent classes shouldn't have to change when your
implementation changes, nor should they care what type of
implementation they receive.
So in that regard, while using the shim may provide a nice way to
abstract some boilerplate, it does break your existing API contracts
and it requires that you define new *Shim contracts that are likely to
duplicate existing API contracts.
If the underlying implementation in the shim is to be created and
delegated to asynchronously, then it is true that each shimmed method
must return void (similar to the RPC async interfaces), and that
imposes some limitation on what we can readily abstract.