1

My Java library provides an interface SomethingClient with one implementation class SomethingClientImpl. The interface contains methods that would be called by the app, as you'd expect.

But there is a "mirrored" interface SomethingHandler, which contains methods that are provided by the app - application callbacks. You can imagine the app provides to the library, an object of this interface - perhaps to the Factory method from which SomethingClient is gotten.

As an unexperienced Java designer, I'm interested to know whether there is a name for, and whether/to what extent is recommended, to also provide an interface and class that combines both concepts:

public interface SomethingClient { /*..*/ }

public interface SomethingHandler { /*..*/ }

public interface ClientAndHandler extends SomethingClient, 
                                          SomethingHandler { }

public abstract class ClientAndHandler_Impl implements ClientAndHandler {

    final SomethingClient clientImpl_;

    ClientAndHandler_Impl(SomethingClient clientImpl) {
        this.clientImpl_ = clientImpl;
    }

    // TODO now all SomethingClient methods are implemented in terms of clientImpl_
    // AND, SomethingHandler methods are left abstract so they are implemented by the application
}

The intent is, the application writer might prefer to extend from the ClientAndHandler_Impl abstract class and implement the callback methods, perhaps in terms of the client (outgoing) methods. This can be done with relative ease. Assuming you'd do it, what name would you give to the ClientAndHandler concept?

Roman
  • 4,922
  • 3
  • 22
  • 31
haelix
  • 4,245
  • 4
  • 34
  • 56
  • I don't know what I'd call it, but I think the `ClientAndHandler` is redundant; `ClientAndHandler_Impl` can implement both `SomethingClient` and `SomethingHandler` – Jacob G. Feb 07 '19 at 21:29
  • 1
    Not sure I understand the construct correctly, but I'd call the implementation of `SomethingClient` by calling a contained implementation object the "Delegate" pattern. – daniu Feb 07 '19 at 21:30
  • @daniu That is useful, basically, the intent is to delegate the `Client` part to a certain implementation, and leave the rest abstract. – haelix Feb 07 '19 at 21:32
  • Why have the `SomethingHandler` interface, and not just have `ClientAndHandler extends SomethingClient` ? Do you have classes that only require `SomethingHandler` methods? – Devin H. Feb 07 '19 at 21:37
  • @DevinH. perhaps it is more orthodox to separate them as a rule of thumb, for example for easier mocking you'd prefer to have the Handler separate. Then again, I can mock the `abstract ClientAndHandler` just fine with `Mockito` and `CALLS_REAL_METHODS` which would preserve the concrete (client) part and only mock the abstract part, but the author advises against. I'm investigating which approach to prefer, separation on one hand is more "SRP" but also having to deal with one concept instead of 2 is beginner-friendly. – haelix Feb 07 '19 at 21:49

2 Answers2

1

Skeletal Implementation

Your current code looks a little bit like the skeletal implementation. You can read more about it on massachusetts institute of technology or on dzon.

The idea behind it is to provide a client with a default implementation. You can find some examples in the Java-Collections-API like AbstractCollection, AbstractSet and AbstractMap.

Some Suggestions

Reduntant Interface

The interface ClientAndHandler is redundant. The class ClientAndHandler_Impl should implement SomethingClient and SomethingHandler.

Naming

I would name the abstract class ClientAndHandler_Impl to AbstractClientInteraction or ClientInteractionSkeleton if you want to make clear that you use the skeletal implementation.

Roman
  • 4,922
  • 3
  • 22
  • 31
  • true that it does look a bit like that, but the Skeleton doesn't contain the concept of incoming/outgoing methods and I haven't seen any conceptual guidance that would differentiate between these (I don't mean in the SO answers but generally) – haelix Feb 08 '19 at 13:24
0

Firstly, this is not a design pattern. It does sort of contain one through: the delegation pattern.

As for combining the interfaces, I might call that a "composite marker interface" or something. I'm not aware of any accepted name for that.

This is bad for a couple of reasons. Firstly, my class could implement A and B separately but if it doesn't implement AAndB then it's not going to match the type of those methods. Generic type intersection is therefore preferable.

Secondly, I believe that requiring a composite type in the first place is indicative of bad design. Classes should do one thing. If you're implementing two distinct interfaces, you're by definition not doing one thing.

Michael
  • 41,989
  • 11
  • 82
  • 128
  • the "one thing" philosophy only goes this far, pragmatically speaking. If in a system, you have one class to do each of 2000 things that need to be done, well, imagine the result – haelix Feb 08 '19 at 13:26
  • @haelix I'm confused. It sounds like you're agreeing me ("one class should not do 2000 things") but you've phrased it as if you disagree with me. – Michael Feb 08 '19 at 13:28
  • I was pondering that if the "one thing" principle is fully adhered to, you can end up with an immense number of abstractions that itself makes the system difficult to comprehend – haelix Feb 08 '19 at 21:34
  • @haelix If you need to do 2000 things, you need to do 2000 things. Dumping those 2000 things into one file doesn't make more maintainable, it makes it less. – Michael Feb 08 '19 at 21:47
  • You are giving an straw-man argument - _Dumping those 2000 things into one file_. I was not proposing one file, but rather, per my original question, fusing 2 concepts into one occasionally, for simpler presentation to an API user. It is true that your API requires 2000 abstractions, but it doesn't mean that they be exposed to the API user as 2000 individual pieces. I don't think we disagree fundamentally. – haelix Feb 09 '19 at 11:16
  • @haelix I think we do. "fusing 2 concepts into one occasionally" is never desirable. – Michael Feb 09 '19 at 12:00