Interface pattern
In computer science, the interface pattern isn't a specific pattern amongst design patterns. It's a general method for structuring programs so that they're simpler to understand. In general, an interface is a class which provides the programmer with the information what operations can be performed on an instance of a class that implements this interface, as opposed to how those operations are internally implemented.
An interface could contain a set of objects and provide simpler, higher-level functions to the programmer (for example, the Façade_pattern); it could provide a cleaner or more specific way of using complicated classes (a "wrapper" class); it could be used to act as the "glue" between two different APIs (the adapter pattern); and much more.
Other kinds of interface patterns are: delegation pattern, composite pattern, and bridge pattern.
Implementation
C++
In opposite to Java, where interfaces are common, this pattern is not very often used in C++. But sometimes it can help to reduce dependencies. For libraries using a facade class to hide the internal implementation to a component the interface pattern can increase the readability of the code.
As the facade class is an interface to the library its header file needs to be available from outside of the library. So it has to be placed in the include directory of the library. But this facade class perhaps needs attributes of other classes of the library. So its header file has to include the header files of the other classes. So these header files also need to be trackable and therefor they have to be placed also in the include directory of the library. Now the strategy, that only the interfaces of the library are defined in its include directory is violated. This problem could be solved by the usage of the interface pattern.
To implement an interface to a class A
an interface class A_Interface
has to be created, defining the interface methods of class A as abstract functions. Class A
has to be derived from this class A_Interface
.
Attention! Do not forget to define the destructor of class
A_Interface
to be virtual!
Then the header file of class A
can reside in the source directory of the library while the header file of class A_Interface
stays as the interface in the include directory.
As the interface class is abstract and the implementation class is unknown from outside of the library, a factory is needed to create objects of class A
. It makes sense to create a class method in the interface class A_Interface
to work as a factory method.
class A_Interface {
public:
static A_Interface* create_A();
virtual ~A_Interface() {}
virtual do_something() = 0;
};
class A : public A_Interface {
public:
do_something();
};
Eiffel
The Eiffel programming language supports multiple inheritance so it doesn't need the Java concept of Interface. Insteed, any class that is deferred acts like an interface. The deferred classes are the classes that have deferred features. At the opposite of Java, these features can express contracts and have default bodies.
The following example shows the interface for some URI getter.
deferred class URI_GETTER feature
uri: URI
is_loaded: BOOLEAN is deferred end
content: STRING is require is_loaded deferred ensure content/=Void end
header: URI_GETTER_HEADER is require is_loaded deferred ensure header/=Void end
clean is deferred ensure not is_loaded end
load is deferred ensure is_loaded end
reload is require is_loaded do load end
end
class URI_GETTER_FTP inherit URI_GETTER creation make feature
make(a_uri: URI) is
require a_uri.method.equals(once "ftp") do
uri:=a_uri; create {URI_GETTER_HEADER_FTP} header end
is_loaded: BOOLEAN is do Result := content/=Void end
content: STRING
header: URI_GETTER_HEADER_FTP
clean is do content:=Void end
load is do ... end
end