Pattern: Interfaces Independent Of Implementation
Many Java frameworks use ParameterClasses that take advantage of the built-in mechanisms for dynamic linking to allow the framework to be extended by third party developers of ParameterClasses.
* * *You are defining a framework that maps external data to ParameterClasses and dynamically loads those classes into the JVM. The dynamically loaded ParameterClasses all implement a a common interface but some ParameterClasses need to offer additional, type-specific services. These services are provided by extending the common interface with additional methods. Users of these extended ParameterClasses can check for additional services with the instanceof operator (or some equivalent mechanism) and then attempting to cast the dynamically loaded object to the extended interface.
If different developers each write a ParameterClass to handle the same type parameter, they will both need to write extended interfaces. Even if these interfaces have the same signature, the JVM will consider them to be different. Thus, a client program cannot dynamically query the plugin for an extended interface without being tied to the vendor that defined that interface. This negates the point of using ParameterClasses in the first place.
Therefore: Define standard extended interfaces for well known or standardised parameters. Third-party plug-ins can implement these interfaces. Clients can query for the standard interfaces, without needing to rely on propriety extensions to the framework.
* * *Definition of InterfacesIndependentOfImplementation may require that the framework be regularly updated with extended interfaces for new parameter types.
Examples of this pattern occur in the Java security framework. E.g. cryptographic keys implement the PublicKey or PrivateKey interfaces. Keys are obtained by requesting keys for a named algorithm: the textual algorithm name is mapped to ParameterClasses, provided by a third-party vendor, that implement the algorithm. Keys for specific algorithms, such as DSA, can provide additional information. Rather than require programs to obtain this information through vendor-specific interfaces, Java security defines standard interfaces for DSA keys that are implemented by vendors of the DSA algorithms.
Comments? --NatPryce
Nat, I'm going to need some example code here. To me this sounds just like the StrategyPattern from the GangOfFour. --KyleBrown
Ok. Taken from my own experience, but simplified somewhat to highlight the important points...
I have implemented a framework for building transport protocols by plugging together components. Protocol components are loaded dynamically. A program will request a protocol component by name and be returned an implementation of that protocol. For example, the name "tcp" is mapped to the TCP protocol. Different vendors may provide implementations of the same protocol: the framework uses a database to map protocol names to specific implementations.
All protocol components implement the Protocol interface. This interface provides methods for transmiting data and plugging protocol layers together. It also allows client code to query for control interfaces on the layer (or those beneath it) so that it can configure the protocol stack it is using.
interface Protocol { void transmit( Message m ) throws TransportException?; void setReceiver( ProtocolReceiver? r ); // who gets called when messages arrive Control getControl( Class control_interface_class ); } interface Control { // Empty - it just marks interfaces as being used to control protocol layers }There are a number of standard control interfaces. For example, to control a connection:
interface ConnectionControl? extends Control { void connect( Address to ) throws TransportException?; void close() throws TransportException?; void shutdown() throws TransportException?; void addConnectionListener( ConnectionListener? l ); void removeConnectionListener( ConnectionListener? l ); }This is a generic interface for controlling a connection-oriented protocol. It allows higher layers to actively connect to a remote peer, independently of the actual protocol implemented by the layer (i.e. TCP, SPX).
However, some protocols have specific options that should be made available to code that needs them. For example, TCP has options to disable the NagleAlgorithm?, configure the size of the send and receive buffers and so on. SPX has different options, as does ATM/AAL5 etc.
Because component implementations are loaded dynamically, and different vendors may provide implementations of the same protocols, there may be more than one implementation of the TCP protocol: for instance, uk.ac.ic.doc.protocols.tcp.TCP and com.mycorp.protocols.tcp.TCP. Without standard control interfaces, different vendors will define control interfaces for their own implementations of TCP. Code wanting to control the TCP protocol is tied to a specific vendor because it queries for the control interfaces by class.
Therefore, the protocol framework defines standard interfaces for controlling TCP and other protocols even though it does not provide implementations of all those protocols itself: it defines InterfacesIndependentOfImplementation. This allows code using those control interfaces remains vendor independent.
The same argument applies when using the instanceof operator to cast to control interfaces.
--NatPryce
Perhaps a better name would be DefineExtendedInterfacesInFramework??
If I got it right, then the best example in Java for this pattern _could_ be the java.net.URLConnection class and its descendents. However, for some reason that eludes me those are abstract classes instead of interfaces, making casting to and obtaining a HttpURLConnection in applets impossible.
That is a good example, although the key classes in the security and crypto packages are closer to the letter of the pattern. However, for most programmers, they are probably much more obscure than the networking classes.
In Java 1.2 and above there is also a JarURLConnection class in the java.net package. The hierarchy could be extended with classes such as FtpURLConnection, GopherURLConnection, FileURLConnection, MailtoURLConnection etc. in the java.net package, with implementations in other packages (such as com.sun.net or whatever).
The use of abstract classes for URLConnections is a limitation. For example, a URL connection can either be a JarURLConnection or an HttpURLConnection but not both. This means that a program cannot control the HTTP connection if HTTP is used to access a JAR file! This is why the pattern suggests using Java interfaces to expose optional controls and parameters rather than abstract classes.
Finally, it is permissable to cast to an abstract class within an applet. What happened when you tried to do so?
--NatPryce
Well, it turns out that the actual implementation of HttpURLConnection in the browser's JVM is not a subclass of java.net.HttpURLConnection but a class with the same name and interface (methods)in a different package. This is implementation's fault, ofcourse, but I believe using interfaces instead of abstract classes would have forced the right implementation.
Hey, that would be InterfacesEnforceImplementation?, wouldn't it ? :)
Interfaces allow implementation is closer. You can never force people not to do the wrong thing, unfortunately.
Actually, this sounds a lot like an adapter to me (ala the AdapterPattern). i.e. One defines an interface and classes that know how to interact with that interface allowing concrete implementations to specialize behavior. For example, Company A may implement the interface differently than Company B. Any thoughts, Nat? -- RobertDiFalco
An Adapter is required if you have a class with one interface and a client class that expects another interface. InterfacesIndependentOfImplementation is a pattern of framework design that helps avoid the need for adapter classes in code built on top of a framework.
(Aside, the name is terrible and I'd like to change it but (a) I haven't thought of a better name and (b) Wiki doesn't have a rename-page mechanism that updates all references to the renamed page.)
--NatPryce