4

Okay I know this question has been asked a few times, but I need an advice on my specific case. There are Encodable's and Decodable's, and a Message is both an Encodable and a Decodable:

interface Encodable { void encode(); }
interface Decodable { void decode(); }
class Message implements Encodable, Decodable { ... }

void processEncodable(Encodable encodable) {
  ...
  encodable.encode();
  ...
}

There are other Encodable's (and Decodable's) besides Message and they need to be processed in processEncodable. So far so good, but the problem is that I want to hide encode() and decode() from outside the package, and Java interface doesn't allow protected/private methods. One might suggest abstract classes, but as you can see Message should inherit both Encodable and Decodable, so that's not the case. Any suggestions?

These days I'm very much into Scala, and Scala traits allow protected/private methods and that's more intuitive IMHO. I've gone through a few answers mentioning Java interface's design philosophy, but I don't really understand why it shouldn't permit protected methods if interface was introduced as an alternative to multiple inheritance, while abstract classes do..

K J
  • 4,505
  • 6
  • 27
  • 45
  • 3
    Why do you think the answer would be different for your case, as opposed to the answers you already mention that you have read? http://stackoverflow.com/questions/5376970/protected-in-interfaces – atk Apr 15 '13 at 18:12
  • 1
    Exactly. Don't try to use interfaces in ways they are not designed for. – Bart Apr 15 '13 at 18:19
  • @atk: because the answer there was not very helpful to me. it says nothing but "that's the way Java is". Plus yes, "an interface is supposed to mean what you can see from outside the class" but why not outside the class and only inside a package, just as an abstract class support? – K J Apr 15 '13 at 18:19
  • I think the question has to be whether it's a good idea to have `Encodable.encode()` return an `Encodable`. That would only make sense if you wanted to encode something twice. Wouldn't it make more sense if `Encodable.encode()` returned a `Decodable`, and `Decodable.decode()` an `Encodable`? At least I would expect something that was encoded to be decodable. – Axel Apr 15 '13 at 18:30

1 Answers1

2

Being an alternative doesn't imply that it is a full substitute. Interfaces are Service Contracts and so they expose the functionalities that a certain class provides to its clients, being a client anyone with access to the interface.

If you want to hide encode and decode from outside the package (that means that your logic should also stay in the package with the Message class) don't expose them through the interface and, instead, allow them to be protected (or package private) methods of your Message class (or a superclass, if various classes will be encodable/decodable).

This is not an isolated rule. There are mechanisms to achieve what you want without breaking the concept of an Interface. Just think about this: What good does that method to the interface if you can access it only inside a package? What's the point of having such methods in an interface if they can be class methods that are, also, available to the members of the package with the proper modifiers?

Fritz
  • 9,987
  • 4
  • 30
  • 49
  • I'm trying to generalize the design thus reuse code as much as possible. There are various encodable classes so I want to avoid putting encode() in Message. And a Message needs to be both encodable and decodable, so superclasses is not an option either as multiple inheritance is not allowed. – K J Apr 15 '13 at 18:36
  • @KJ I don't see why your superclass can't be `Encodable` and have both encode/decode methods. Is there such a case where a class is encodable but not decodable or viceversa? It doesn't make much sense to me but if that's your case you can either use an UnsupportedOperationException or a flag to indicate such behaviour. – Fritz Apr 15 '13 at 18:41
  • Exactly, an encodable object isn't necessarily decodable and vice versa. A message is only a special case where they intersect. Encoding operation is different from decoding operation and I'd like to separate them into different modules if possible. – K J Apr 15 '13 at 18:49
  • @KJ Indeed encoding and decoding are different operations, but why should an object be encodable and not decodable? Are they going to be decodable in the future or are they to be decoded by a third party? They can't remain encoded forever. I'm just trying to get to understand your context so we can come up with the best alternative. I think the issue here also covers some design areas. – Fritz Apr 16 '13 at 14:13