Monday, October 13, 2014

OO Programming with ABAP Objects: Interfaces

Throughout the course of this blog series, we have covered the basic cornerstones of object-oriented programming including:



In this final installment of the series, we will expand upon the concept of inheritance/polymorphism by introducing you to the concept of interfaces.


Why do we need interfaces?


In my previous OO Programming with ABAP Objects: Polymorphism, we explored the notion of interface inheritance and showed you how to use it to implement polymorphic designs. Here, the basic premise is that since a subclass inherits the public interface of its superclass, you can invoke methods on an instance of a subclass in exactly the same way that you call them using an instance of the superclass. As we learned, you can leverage this functionality to develop generic methods that can work with an instance of the superclass or any of its subclasses. This is all fine and well when you're working with classes that fit neatly into a particular inheritance model. But what happens when you want to plug in functionality from a class that already has an inheritance relationship defined?

In some programming languages, it is possible to define multiple inheritance relationships in which a given class can inherit from several parent classes. For instance, in the UML class diagram below, class D inherits from classes B and C. Though the concept of multiple inheritance may sound appealing on a conceptual level, it can cause some serious problems on an implementation level. Looking at the UML class diagram below, consider the inheritance of method "someMethod()" for class D. Here, let's assume that classes B and C have overridden the default implementation of this method from class A. Based on this, which implementation of method "someMethod()" does class D inherit: the one from class B or class C? In object-oriented programming parlance, this conundrum is referred to as the diamond problem.

Diamond Problem

Rather than try and tackle multiple inheritance issues such as the diamond problem, the designers of the ABAP Objects language elected to adopt a single inheritance model. This implies that a class can only inherit from a single parent class. This does not mean, however, that you cannot implement multiple inheritance in ABAP. Rather, you simply must go about defining it in a different way using interfaces.

In order to explain the concept of interfaces, it is helpful to see an example of how they are used in code. Consider the LIF_COMPARABLE interface shown below. This interface defines a single method called "compare_to()" that returns an integer indicating whether or not an object is less than, greater than, or equal to another object of the same type. As you can see, we have only defined the method here; there is no implementation provided. Indeed, you are not even allowed to provide implementations within an interface definition.

INTERFACE lif_comparable.
METHODS:
compare_to IMPORTING im_object TYPE REF TO object,
RETURNING VALUE(re_result) TYPE i.
ENDINTERFACE.

Looking at the definition of the LIF_COMPARABLE interface above, you might be wondering why we would want to bother defining an interface. After all, they don't anything particularly exciting. Still, much like classes, it does encapsulate a unique concept: comparability. Comparability is a feature that we would like to implement in a number of different classes. In fact, defining comparability in a common interface enables us to develop generic algorithms for sorting objects, etc. The question is how. Since many of the classes we want to implement this with likely have pre-existing inheritance relationships, we can't define the comparison functionality in a common superclass. However, we can model this functionality in an interface.

Taking our comparability example a step further, let's imagine that we want to define a sort order for a set of customer objects of type LCL_CUSTOMER. For the purposes of our discussion, let's assume that class LCL_CUSTOMER inherits from a base business partner class called LCL_PARTNER. In order to assume the comparability feature, LCL_CUSTOMER also implements the LIF_COMPARABLE interface as shown below.

CLASS lcl_customer DEFINITION
INHERITING FROM lcl_partner.
PUBLIC SECTION.
INTERFACES: lif_comparable.
"Other declarations here...
ENDCLASS.

CLASS lcl_customer IMPLEMENTATION.
METHOD lif_comparable~compare_to.
"Implement comparison logic here...
ENDMETHOD.
ENDCLASS.
Looking at the code excerpt above, you can see that we have split class LCL_CUSTOMER into two dimensions: a customer is a partner; but it is also comparable. This means that we can substitute instances of class LCL_CUSTOMER anywhere that the interface type LIF_COMPARABLE is used.

Now that you have a feel for how interfaces are used, let's attempt to define interfaces a little more formally. An interface is an abstraction that defines a model (or prototype) of a particular entity or concept. As you saw above, you don't define any kind of implementation for an interface; that is left up to implementing classes. Once a class implements an interface, it fulfills the requirements of an inheritance relationship with the interface. In this way, you can implement multiple inheritance using interfaces. Indeed, classes are free to implement as many interfaces as they wish.


How can I use interfaces in my own designs?


Hopefully by now you can see the power of interfaces, but you may be unsure of how to use them in your own designs. In these early stages of development, it is helpful to look around and see how others are making use of interfaces. In particular, we can look to see how SAP uses interfaces in various development objects. Some of the more common places where interfaces are used extensively by SAP include:



  • The iXML Library used to parse XML in ABAP.

  • The ABAP Object Services framework that enables object-relational persistence models.

  • The Web Dynpro for ABAP (WDA) context API.

  • Business Add-Ins (BAdIs)

  • The Internet Communication Framework (ICF) used to send and receive HTTP request messages.

If you have ever worked with BAdIs before, then perhaps you may have interacted with interfaces without even realizing it. BAdIs are a type of customer enhancement in which customers can implement a "user exit" that supplements core behavior with custom functionality. The screenshot below shows the definition of a BAdI called "CTS_REQUEST_CHECK". This BAdI is used to validate a Change and Transport System (i.e. CTS) transport request at various important milestones. On the Interface tab, notice the interface name "IF_EX_CTS_REQUEST_CHECK". This interface defines the methods "check_before_creation()", etc. shown below. Whenever we create a BAdI implementation for "CTS_REQUEST_CHECK", the system will generate a class that implements this interface behind the scenes. At runtime, the CTS system will invoke these methods polymorphically to implement the desired user exit behavior.

BAdI Definition for CTS_REQUEST_CHECK

The BAdI example above provides us with some useful observations about interfaces:



  1. Interfaces are particularly well suited to modeling behavior. In other words, while classes are often representation of nouns, interfaces can often be used to supplement these core entities with different types of behavior, etc.

  2. Interfaces make it possible to implement polymorphism in a lot of different ways. For example, if a pre-existing class contained functionality to handle CTS request milestones, then we could implement the IF_EX_CTS_REQUEST_CHECK interface in that class rather than reinventing the wheel.

  3. Interfaces allow you to further separate the API interface from its underlying implementation.

Based on these observations, we would offer the following rule of thumb:  when developing your OO designs, try and represent your core API using interfaces. This step helps ensure that your design remains flexible over time. An excellent example of this is the iXML Library used to process XML in ABAP. The only concrete class provided in the iXML Library is the CL_IXML factory class - everything else is interface-driven. This abstraction makes it possible for SAP to neatly swap XML parser implementations behind the scenes without anyone knowing the difference. Similarly, if your core API is represented using interfaces, you have much more flexibility at the implementation layer. Over time, you'll thank yourself for putting in the effort up front.

An excellent resource for coming up to speed with interfaces is the classic software engineering text Design Patterns: Elements of Reusable Object-Oriented Software (Addison-Wesley, 1994). This book allows you to enter the mind of object-oriented pioneers who have documented many useful OO design patterns in an easy-to-read catalog-based format. Digging into these designs, you'll see how interfaces can be used to implement certain types of flexibility that simply cannot be realized with basic inheritance. You'll especially appreciate the ABAP Objects implementation when you see how the authors struggle to implement certain functionality in C++ (which does not support interfaces).


Closing Thoughts and Next Steps


I hope that you have enjoyed this blog series as much as I have enjoyed writing it. Thanks to everyone for their kind and useful feedback; it is much appreciated. In many ways, this series barely scratches the surface of the possibilities of OO programming. If you are interested in learning more, might I offer a shameful plug for my book Object-Oriented Programming with ABAP Objects (SAP Press, 2009). Here, I cover these topics (and more) in much more depth. Best of luck with your object-oriented designs!

Object-Oriented Programming with ABAP Objects
Post a Comment