© James E. McDonough 2017

James E. McDonough, Object-Oriented Design with ABAP, 10.1007/978-1-4842-2838-8_7

7. Interfaces

James E. McDonough

(1)Pennington, New Jersey, USA

The next stop on our journey to Objectropolis takes us from Polymorphism to a place called Interfaces.

The term interface has multiple meanings within the data processing industry. The ubiquitous GUI interface enables people to interact with a software system. Many ABAP programmers are familiar with the acronym RICEF, in which the “I” represents Interfaces and most often is associated with data exchanges with external systems. The signature for function modules is known as its interface. With such ambiguity already associated with this word, it is unfortunate that the word also has a specific meaning in the object-oriented programming context. The word interface is qualified sometimes as an independent interface 1 to distinguish it from all these other contexts, where its modifier independent denotes that the interface is not associated with a GUI, or a process for exchanging data with an external system or for specific signature recognition of function modules, but simply that it is independent, disconnected from any specific use.

Supplementing Public Visibility of Classes

Interface is a description of a feature available in some but not all object-oriented programming environments, and it is one available to both Java and ABAP environments. In the object-oriented context, an interface is a set of definitions for data types, constants, and/or methods that can be used by a class as a supplement to its own public visibility. Just as a class can indicate that it inherits from another class, a class similarly can indicate that it uses an interface. A class using an interface is said to implement the interface. This concept of implementing an interface arises mostly from the fact that, unlike a class, an interface containing method definitions provides no implementation for those methods, each of which is defined in the interface only to establish the name of the method and its signature . It is the responsibility of the class implementing the interface to provide implementations for every method defined by the interfaces it uses.

Indeed, those methods defined by an interface used by a class must be implemented by the class. This is similar to the idea that abstract methods defined in parent classes must be implemented by the child classes inheriting from them.

In many ways, an interface definition is similar to a class definition; however, with interface there is no concept of a visibility level for its members, since all members contributed by an interface to a class implicitly have public visibility. Often programmers will assign names to interfaces to denote the new capability that it confers upon a class implementing it. These names frequently end with the suffix “able” (or its cousin “ible”).

I am often asked by students why an interface contributes only members with public visibility. Why, they ask, can the class implementing the interface not define implementations for its methods with protected or private visibility? This is a good question. The answer is that the use of interfaces is a proclamation by the class to other external entities for the types of members it offers publicly. Accordingly, all of these other entities can rely on implementations provided by the class to be publicly accessible. For a class to proclaim it implements an interface and then to provide any one of the implementations of the interface's methods with private visibility means the external users of the class would not have access to all the capabilities afforded by the interface. In effect, implementing an interface is a declaration by the class that it is making all of the members of the interface accessible to external entities.2 We will see later in the section on Design Patterns a pattern where multiple classes implementing the same interface are considered interchangeable. Accordingly, we cannot have each class deciding for itself which interface members it will make publicly available, lest they would no longer be interchangeable.

Let’s see an example of an interface that provides definitions for attributes and methods to facilitate fuel consumption. The name of this interface is fuelConsumable and it provides the following public data types for use by those classes implementing it:

consumptionRate

type integer

consumptionUnit

type unit of measure

fuelUnit

type unit of measure

fuelType

type string

fuelQuantity

type integer

remainingFuelPercentage

type decimal (five digits representing nnn.nn)

remainingConsumptionUnits

type integer

The fuelConsumable interface defines these data types but not the actual data fields themselves, leaving to the class the responsibility to define corresponding attributes. Accordingly, the class can use the data types from the interface to define the attributes while at the same time retaining control over their visibility. Had the interface itself defined the actual data fields, then they would be publicly visible. By having the interface define only the types of data and relegating to the class the responsibility to define the data fields, the class can now assign these attributes a visibility level other than public .

The fuelConsumable interface also provides the following public setter methods associated with specific attributes, where the type of data to be exchanged is shown in parenthesis following the method name:3

  • setConsumptionRate(consumptionRate)

  • setConsumptionUnit(consumptionUnit)

  • setFuelUnit(fuelUnit)

  • setFuelType(fuelType)

  • setFuelCapacity(fuelQuantity)

  • setFuelLevel(fuelQuantity)

plus the following public getter methods associated with specific attributes:

  • getConsumptionRate(consumptionRate)

  • getConsumptionUnit(consumptionUnit)

  • getFuelUnit(fuelUnit)

  • getFuelType(fuelType)

  • getFuelCapacity(fuelQuantity)

  • getFuelLevel(fuelQuantity)

and the following methods which have no single associated attribute:

  • calculatePercentageFuelRemaining(remainingFuelPercentage)

  • estimateFuelExhaustion(remainingConsumptionUnits)

An interface will often provide the data types it uses for parameters in the signatures of the methods it also defines, as we see in the fuelConsumable interface which defines the data type remainingFuelPercentage used with the signature of method calculatePercentageFuelRemaining. This way the caller of those methods can define corresponding parameter exchange fields in terms of the data types defined by the interface. In addition, an interface may provide constants defined using those data types, so that callers of those methods will have predefined and descriptive constants to be used as compatible signature parameter values passed into the methods.

Suppose class Car is defined to implement the fuelConsumable interface. This means that Car must provide implementations for all 14 methods defined by the interface. A simple approach to this is to define private attributes in the Car class to correspond to each of the “set” methods contributed by the interface, using data types defined by the interface. Then, the implementation of each set method will copy the value from the method parameter to the private attribute of the class. Each get method will do the reverse of its corresponding set method, copying the value from the private attribute of the class to the method parameter.

Finally, the method calculatePercentageFuelRemaining will return the value for the following expression:

  • remainingFuelPercentage = currentFuelLevel * 100 / fuelCapacity

The method estimateFuelExhaustion will return the value for the following expression:

  • remainingConsumptionUnits = currentFuelLevel * consumptionRate

Based on this, Listing 7-1 shows some pseudocode for a program to track the fuel consumption of a car.

Listing 7-1. Pseudocode to Track the Fuel Consumption of a Car
unused_fuel_capacity   type fuelConsumable.remainingFuelPercentage
remaining_consumption  type fuelConsumable.remainingConsumptionUnits
consumption_unit       type fuelConsumable.consumptionUnit
this_car               type reference to class car


create new instance of car object into this_car
invoke behavior setConsumptionRate     of this_car with "30"
invoke behavior setConsumptionUnit     of this_car with "Miles"
invoke behavior setFuelUnit            of this_car with "Gallon"
invoke behavior setFuelType            of this_car with "Gasoline"
invoke behavior setFuelCapacity        of this_car with "14"
invoke behavior setFuelLevel           of this_car with "05"
  o
  o
  o
invoke behavior calculatePercentageRemainingFuel
                                       of this_car
                                          with unused_fuel_capacity
invoke behavior estimateFuelExhaustion of this_car
                                          with remaining_consumption
invoke behavior getConsumptionUnit     of this_car
                                          with consumption_unit
display "this_car unused fuel capacity :"
      , unused_fuel_capacity
      , "%"
display "this_car remaining consumption:"
      , remaining_consumption
      , consumption_unit

The result of executing this program is the following lines:

this_car unused fuel capacity : 36 %
this_car remaining consumption: 150 Miles

Let’s expand on this idea . Table 7-1 shows an example of the attribute values associated with some additional classes implementing the fuelConsumable interface after the program instantiating them has executed to the point of having invoked the various set methods to set values for all the corresponding attributes associated with fuel consumption defined by each class.

Table 7-1. Attribute Values Associated with Classes Implementing the fuelConsumable Interface
 

Interface attributes

Class implementing interface

Consumption rate per 1 fuel unit

Consumption unit

Fuel unit

Fuel type

Capacity in fuel unit

Current level in fuel unit

Car

30

Miles

Gallon

Gasoline

14

5

Truck

6

Miles

Gallon

Diesel

300

200

Cabin

2

Weeks

Cord

Wood

8

8

Cell Phone

60

Minutes

Milli-amp hour

Electricity (Lithium ion battery)

720

120

Gas Grill

91,500

BTU

Gallon

Propane

20

5

Coal-Fired Power Plant4

4

Seconds

Ton

Coal

1,296,000

648,000

The column titled “Class implementing interface” describes the type of class that implements the fuelConsumable interface. Subsequent columns represent values for the attributes defined in the class, using the corresponding data types defined by the interface, for tracking fuel consumption. In each case, the corresponding class provides implementations for each of the methods defined by the interface. For our simple example here, the get and set methods can be implemented in each class similarly to how we saw them implemented for the Car class shown in Listing 7-1, with each set method setting the value for its corresponding attribute of the class and each get method getting the value for its corresponding attribute of the class. Indeed, the implementations for methods calculatePercentageFuelRemaining and estimateFuelExhaustion for each of these classes can use the very same implementation as defined for the Car class.

Interface Reference Variables

At this point, it may occur to us that there seems to be no advantage to using an interface; we could have provided all of these fuel consumption attributes and methods directly for these classes. After all, we had to provide an implementation for every method, so we did not gain much in the way of reusing code . While all of this is true, it overlooks one of the most powerful capabilities that interfaces provide for object-oriented programming, which is this:

  • As with class, an interface may be defined as the data type defined for a reference variable.

Just as we can define a variable with type reference to a class, we can also define a variable with type reference to an interface. When we do, the corresponding interface reference variable may hold a reference to an instance of any class implementing the interface . A class may define members beyond those defined by the interface; however, when the instance of the class is accessed via an interface reference variable, only those members of the class defined by the interface are accessible.

With only class reference variables, we would need to define six different variables to hold references to the Car, Truck, Cabin, Cell Phone, Gas Grill, and Coal-Fired Power Plant of the preceding chart. By contrast, we could define a single variable as type reference to fuelConsumable and have it hold a reference to any one of the six classes implementing the fuelConsumable interface.

Listing 7-2 shows the pseudocode we saw in Listing 7-1 altered to use an interface reference variable instead of a class reference variable, with differences from Listing 7-1 highlighted.

Listing 7-2. Pseudocode Using an Interface Reference Variable, with Differences from Listing 7-1 Highlighted
unused_fuel_capacity   type fuelConsumable.remainingFuelPercentage
remaining_consumption  type fuelConsumable.remainingConsumptionUnits
consumption_unit       type fuelConsumable.consumptionUnit
this_fuel_consumer     type reference to interface fuelConsumable


create new instance of car object into this_fuel_consumer
invoke behavior setConsumptionRate     of this_fuel_consumer with "30"
invoke behavior setConsumptionUnit     of this_fuel_consumer with "Miles"
invoke behavior setFuelUnit            of this_fuel_consumer with "Gallon"
invoke behavior setFuelType            of this_fuel_consumer with "Gasoline"
invoke behavior setFuelCapacity        of this_fuel_consumer with "14"
invoke behavior setFuelLevel           of this_fuel_consumer with "05"
  o
  o
  o
invoke behavior calculatePercentageRemainingFuel
                                       of this_fuel_consumer
                                          with unused_fuel_capacity
invoke behavior estimateFuelExhaustion of this_fuel_consumer
                                          with remaining_consumption
invoke behavior getConsumptionUnit     of this_fuel_consumer
                                          with consumption_unit
display "this_fuel_consumer unused fuel capacity :"
      , unused_fuel_capacity
      , "%"
display "this_fuel_consumer remaining consumption:"
      , remaining_consumption
      , consumption_unit

As indicated by the highlighting, we only renamed variable this_car to this_fuel_consumer and changed its definition from “reference to class car” to “reference to interface fuelConsumable.” Nothing else needs to change.

Notice we are creating an instance of class car into the variable defined as reference to interface fuelConsumable with the statement:

create new instance of car object into this_fuel_consumer

Interfaces and Polymorphism

The concept of static type and dynamic type is applicable to interface reference variables in exactly the same way it is applicable to class reference variables. The static type of a reference variable is whatever entity follows it in its definition, which in the case of this_fuel_consumer is “type (reference to) interface fuelConsumable.” Its dynamic type becomes “type (reference to) class car” when we create a car instance into this interface reference variable as shown in the statement above. We saw in the chapter on inheritance , where we specified that the car class inherits from the vehicle class, that because car “is a” vehicle it is permissible for a reference to a car object to occupy a vehicle class reference variable . The same concept applies to interfaces, where we say that a class “implements a” interface, such as in this case where the car class “implements a” fuelConsumable interface. Since car “implements a” fuelConsumable, it is permissible for a reference to a car object to occupy a fuelConsumable interface reference variable .

Accordingly, it should come as no surprise that since the static type and dynamic type of an interface reference variable can be different, when they are different, then polymorphism is at work. Indeed, with references to interfaces we will find that the static type and dynamic type are always different because we cannot create instances of interfaces, but only instances of classes implementing those interfaces . Recall that with polymorphism, the actual method executed for a reference variable is determined at runtime through the technique known as dynamic dispatch. As such, it is at runtime, when the fuelConsumable interface variable is found to be holding a reference to a car instance, that the statement

invoke behavior estimateFuelExhaustion of this_fuel_consumer
                                          with remaining_consumption

will determine it is the implementation of this method in the car instance that is to be invoked.

The interface reference variable enables access only to those members of an implementing class that are defined by the interface . So even though our car instance may have methods defined specifically for the car, such as start, stop, accelerate, and turn, these methods are not accessible through the fuelConsumable interface reference variable. This applies equally to all of the other classes implementing fuelConsumable. A truck class may have defined for it methods load and unload, a cabin class may have methods open_chimney_flue_damper and close_chimney_flue_damper, a cell phone may have method redial, a gas grill may have method adjust_gas_flow, and coal-fired power plant may have method shutdown, but none of these methods are available via a reference variable defined as type reference to fuelConsumable.

In the chapter on polymorphism we saw an example of using a superclass, boat, composed entirely of abstract methods, inherited by classes motorBoat and sailBoat (Listings 6-1 through 6-3). Such a superclass would be a good candidate for definition as an interface instead of a class. Let's examine the implications of this using the same example, but where boat is now defined as an interface.

First, let’s change the boat definition from abstract class to interface, as shown in Listing 7-3.

Listing 7-3. Boat Changed from Abstract Class to Interface, with Differences from Listing 6-1 Highlighted
interface boat
                  method start
                  method turnLeft
                  method turnRight
                  method stop
endinterface

The difference between this pseudocode and its superclass counterpart, as indicated by the highlighting, is that we have replaced abstract class with interface and endclass with endinterface. Also, we have removed the method qualifiers public and abstract; both of these qualifiers are implicit in an interface, which always confers public visibility to its members implemented by a class (so no need for the public visibility qualifier) and provides no implementations for its methods (so no need for the abstract qualifier).

Our motorBoat class from Listing 6-2 no longer inherits from the boat class, but as shown in Listing 7-4 now implements the boat interface and provides an implementation for every method defined by the boat interface just as it needed to provide one for every method defined by boat when it was defined as an abstract class.

Listing 7-4. motorBoat Class Changed from Inheriting from a Superclass to Implementing an Interface , with Differences from Listing 6-2 Highlighted
class motorBoat implements boat
  public method start
    engage propeller
  endmethod
  public method turnLeft
    rotate steering wheel counterclockwise
  endmethod
  public method turnRight
    rotate steering wheel clockwise
  endmethod
  public method stop
    disengage propeller
  endmethod
endclass

Also, the sailBoat class from Listing 6-3 no longer inherits from the boat class, but as shown in Listing 7-5 now implements the boat interface and provides an implementation for every method defined by the boat interface just as it needed to provide one for every method defined by boat when it was defined as an abstract class.

Listing 7-5. sailBoat Class Changed from Inheriting from a Superclass to Implementing an Interface , with Differences from Listing 6-3 Highlighted
class sailBoat implements boat
  public method start
    raise sail
  endmethod
  public method turnLeft
    push tiller to right
  endmethod
  public method turnRight
    push tiller to left
  public endmethod
  method stop
    lower sail
  endmethod
endclass

And finally, the marina class from Listing 6-4 changes only to indicate for one of its method signatures that boat is now an interface and no longer a class, as shown in Listing 7-6.

Listing 7-6. Change to Signature of Method of Marina Class to Regard Reference to Interface Instead of Class, with Differences from Listing 6-4 Highlighted
class marina
  public method launchMotorBoat
    thisMotorBoat                 type class of motorBoat
    create new instance of motorBoat into thisMotorBoat
    call method maneuverBoat(thisMotorBoat)
  endmethod
  public method launchSailBoat
    thisSailBoat                  type class of sailBoat
    create new instance of sailBoat into thisSailBoat
    call method maneuverBoat(thisSailBoat)
  endmethod
  private method maneuverBoat(thisBoat type interface of boat)
    invoke behavior start     of thisBoat
    invoke behavior turnLeft  of thisBoat
    invoke behavior turnRight of thisBoat
    invoke behavior stop      of thisBoat
  endmethod
endclass

In the end, we have transformed the definition for boat from a class to an interface without changing much in the way the components already had been defined. The editing changes we made may seem insignificant, and perhaps at first glance not worth our attention. However, the larger consideration here is that these minor changes resulted in two classes, motorBoat and sailboat, no longer inheriting from a superclass. In environments that do not support multiple inheritance , this can be a significant advantage. It provides more flexibility for classes motorBoat and sailBoat to inherit from some other superclass without affecting their ability to provide visibility to these entities simply as boats.

Indeed, we should consider that the entire set of members defined by the boat interface would also be applicable to entities that are not boats. Accordingly, we might define the interface using a word that does not connote anything about boats – perhaps, maneuverable – as in the updated version of pseudocode shown in Listing 7-7, with differences from the components of preceding listings highlighted.

Listing 7-7. Definition of Components to Reduce Reference to Boat Entity, with Changes and Additions to Preceding Listings Highlighted
interface maneuverable
                  method start
                  method turnLeft
                  method turnRight
                  method stop
endinterface


class motorBoat implements maneuverable
  public method start
    engage propeller
  endmethod
  public method turnLeft
    rotate steering wheel counterclockwise
  endmethod
  public method turnRight
    rotate steering wheel clockwise
  endmethod
  public method stop
    disengage propeller
  endmethod
endclass


class sailBoat implements maneuverable
  public method start
    raise sail
  endmethod
  public method turnLeft
    push tiller to right
  endmethod
  public method turnRight
    push tiller to left
  public endmethod
  method stop
    lower sail
  endmethod
endclass


class boatMover implements maneuverable
  public method start
    release brake
    engage drive wheels
  endmethod
  public method turnLeft
    move joystick to the left
  endmethod
  public method turnRight
    move joystick to the right
  public endmethod
  method stop
    disengage drive wheels
    apply brake
  endmethod
endclass


class marina
  public method launchMotorBoat
    thisMotorBoat                 type class of motorBoat
    create new instance of motorBoat into thisMotorBoat
    call method maneuver(thisMotorBoat)
  endmethod
  public method launchSailBoat
    thisSailBoat                  type class of sailBoat
    create new instance of sailBoat into thisSailBoat
    call method maneuver(thisSailBoat)
  endmethod
  public method moveBoatToLandStorage
    thisBoatMover                 type class of boatMover
    create new instance of boatMover into thisBoatMover
    call method maneuverBoat(thisBoatMover)
  endmethod
  private method maneuver(thisManeuverable
                                type interface of maneuverable)
    invoke behavior start     of thisManuverable
    invoke behavior turnLeft  of thisManuverable
    invoke behavior turnRight of thisManuverable
    invoke behavior stop      of thisManuverable
  endmethod
endclass

As indicated by the highlighted changes, we have done the following:

  • Changed the name of the interface from boat to maneuverable

  • Included a new class boatMover defining a boatyard management vehicle which implements the maneuverable interface

  • Changed the name of the sole private method of the marina class so it longer suggests applying only to boats

  • Included in the marina class a new public method for moving boats from the water to land storage

Accordingly, this interface , with its more generalized name, can now apply to things other than just boats, expanding its usefulness to other classes requiring maneuverability.

Interfaces and Inheritance

One of the primary reasons for using interfaces with classes is to achieve the equivalent of multiple inheritance. There is no limit to the number of interfaces a class can implement, and therefore is one way to effectively inherit from multiple contributors. This may account for why interfaces are not indigenous to all object-oriented environments, since those supporting multiple inheritance would not require interfaces as a means to circumvent the restrictions arising from single inheritance.

Let’s see how this might work. In the chapter on inheritance we saw an example of a class inheritance hierarchy diagram (Figure 5-4, presented again here in Figure 7-1), where class dog inherits from multiple classes. We recognized this to be an example of multiple inheritance, where a class has more than one direct ancestor class, with the dog class inheriting from both the canine and domesticPet classes.

A447555_1_En_7_Fig1_HTML.jpg
Figure 7-1. Inheritance hierarchy where class dog illustrates multiple inheritance

The corresponding chart from Table 5-4, presented again here in Table 7-2, describe some instance attributes and behaviors that might be associated with each class .

Table 7-2. Classes and Their Members for the Inheritance Hierarchy Described by Figure 7-1

Class

Attributes

Behaviors

animal

height

weight

age

alacrity

eat

sleep

speak

mammal

 

nurseOffspring

canine

furColor

run

jump

followScentTrail

domesticPet

petName

ownerName

lastVeterinarianVisit

getPetName

setPetName

visitVeterinarian

dog

 

chaseCat

fetch

fox

 

raidChickenCoop

In order to accommodate the approximation of multiple inheritance for the dog class in those environments supporting only single inheritance and also supporting interfaces, we can define class domesticPet as an interface and indicate for the dog class that it implements the domesticPet interface. This will require the dog class to provide implementations for behaviors getPetName, setPetName, and visitVeterinarian, but is an effective way to confer upon the dog class the members defined for both the canine class, from which it inherits, and the domesticPet interface, which it implements, two contributors that do not lie in the same inheritance hierarchy.

Class Coupling

There still is one more aspect of interfaces to be discovered. A class that references another class is said to be coupled to the other class. Class coupling reflects the degree to which each program module relies on each of the other modules.5 A class that invokes a method of another class is more tightly coupled to that class than a class that simply has an attribute defined as a reference to the class but calls none of its methods.

Because a variable can be defined as a reference to an interface, this presents the capability of defining signatures for methods that can exchange such interface references. Accordingly, a method signature may indicate that it accepts a parameter defined as a reference to an interface. The implementation of that method may now use the interface reference variable provided through the signature to invoke upon that instance any of the methods defined by the interface without ever knowing the type of class it is using. It knows only whatever type of class to which the interface reference variable points, it surely has provided implementations for all of the methods contributed by the interface the class proclaims it implements.

Much of the power of an interface lies in this ability to see only that subset of a class corresponding to the interface definition. Accordingly, our program may not know whether the fuelConsumable interface reference variable holds a reference to an instance of a Car, a Truck, a Cabin, a Cell Phone, a Gas Grill, or a Coal-Fired Power Plant, but it certainly knows that it can invoke its method estimateFuelExhaustion and get an answer. This aspect is known in object-oriented programming as loose coupling.

Loose coupling occurs when one class makes use of another class without explicitly referring to the other class by its class name. That is, class A is able to invoke a behavior of class B without mentioning class B by name. Loose coupling is facilitated when a class uses a reference to an interface instead of a reference to a concrete class.6

Refer to Listing 7-7 describing interface maneuverable and a classes sailBoat, motorBoat, boatMover, and marina. Classes sailBoat, motorBoat, and boatMover all implement the maneuverable interface. Class marina has private method called maneuver with a signature accepting a reference to an instance of a class through the maneuverable interface. This private method invokes the start, turnLeft, turnRight, and stop behaviors of an instance of class sailBoat, motorBoat, or boatMover depending on which of the other methods of the marina class invokes the maneuver method. Accordingly, method maneuver is oblivious to which type of class it is using; it only knows that the instance it has been sent by the caller through its signature is a class implementing the maneuverable interface . When method launchSailBoat invokes method maneuver, it sends an instance of class sailBoat as a parameter, but method maneuver regards this merely as an instance of a class implementing the maneuverable interface. As such, method maneuver is capable of invoking behaviors of a sailBoat instance without ever referring to it by its class name.

Loose coupling provides for more flexible design since the class using the interface reference is not bound to any specific type of class. In our fuel consumption example, a program that uses a reference variable to the fuelConsumable interface can work with any type of class implementing this interface. By contrast, had these classes not implemented the fuelConsumable interface, then a program would need to use a reference variable corresponding to the specific type of class to use (Car, Truck, Cabin, etc.) for its processing, and as a consequence would become tightly bound to that class.

Recall the discussion on the topic of cohesion from the chapter on abstraction. Class coupling and class cohesion generally have an inverse relationship to each other. As the cohesion of a class becomes lower, its class coupling usually becomes tighter. That is, low class cohesion usually promotes tight coupling whereas high class cohesion promotes loose coupling . We should strive to define classes having high cohesion and loose coupling, and it is often through the use of interfaces that we can achieve this result.

ABAP Language Support for Interfaces

The object-oriented extensions to the ABAP language accommodate interfaces in the following ways:

  • By facilitating the definition of independent interfaces

  • By supporting the use of independent interfaces in class definitions

  • By supporting aliases within classes for members contributed by interfaces

  • By enabling polymorphism through the use of interface reference variables

Interfaces are defined using the interface construct, which, unlike the complementary class constructs, requires only one construct to contain its entire definition:

interface interface-name.
  [types ...]
  [constants ...]
  [method interface_method_name [signature] ...]
  o
  o
endinterface.

A class indicates those interfaces it implements by naming them on an interfaces statement placed in the public visibility section of the class definition:

class class-name definition [options].
  public section.
    interfaces interface-name.
  o
  o
endclass.

It should be noted that while a class can indicate only a single class from which it inherits, there is no limit to the number of interfaces a class can implement. Both class and non-class components can access any types and constants defined by the interface through the class component selector (=>):

report.
  o
  o
  o
data this_variable type interface_name=>type_name.
  o
  o
  o
if this_variable eq interface_name=>constant_name.

Class components can provide implementations for the methods defined by the interface by providing a compound method name using the interface name and method name separated by the interface component selector (∼):

class class-name implementation.
  method interface_name∼method_name.
    o
    o
    o
  endmethod.
  o
  o
  o
endclass.
  o
  o
  o
  call method interface_name∼method_name.

Use of this compound method name to refer to interface components allows for multiple interfaces implemented by a class to contain the same component names. For instance, class car can implement interfaces named maneuverable and fuel_consumable, both of which define method engage_safety_monitor, and by qualifying references to method engage_safety_monitor by its interface name enables both same-named methods to coexist in the car class. A class may also provide alternative names for those members contributed by the interface by naming them on an aliases statement, alleviating the need to use the interface selector technique when referencing the member contributed by the interface:

class class-name definition [options].
  public section.
    interfaces interface-name.
    aliases alias_name for interface_name∼method_name.
  o
  o
endclass.
class class-name implementation.
  method alias_name.
    o
    o
    o
  endmethod.
  o
  o
  o
endclass.
  o
  o
  o
  call method alias_name.

Polymorphism also is available through the use of interfaces:

interface fuel_consumable.
  methods estimate_fuel_exhaustion [signature].
  o
  o
class car definition.
  public section.
    interfaces fuel_consumable.
  o
  o
  data this_car             type ref to car.
  data this_fuel_consumable type ref to fuel_consumable.
  o
  o
  create object this_car
  this_fuel_consumable      = this_car.
  call method this_fuel_consumable->estimate_fuel_ exhaustion [signature].
  o
  o

Orienting Ourselves After Having Traversed Interfaces

We have reached the last leg of the path in our journey from Procedureton to Objectropolis, and now, having completed our traversal through the object-oriented district known as Interfaces we are familiar with its principles and now are fluent in the language spoken by its residents.

As we found with both Inheritance and Polymorphism , Interfaces also offers no recognizable guideposts or familiar terrain, appearing to us as yet another exotic landscape with no counterpart in our home town of Procedureton. Nonetheless, we are now as familiar with this district as the residents who live here and we are as capable as the native population in navigating our way around Interfaces.

Refer again to the chart in Appendix A, illustrating the comparison between function groups and classes of how each one facilitates the capabilities of the principles of object-oriented programming. Row 17 shows how these two programming formats support the principles of independent interfaces. We see that function groups have no support for this principle; it also is unique to classes.

Summary

In this chapter, we became more familiar with the object-oriented concept of interfaces, a principle not applicable to all object-oriented environments. We learned that independent interfaces contain definitions for attribute types and method signatures but contain no associated method implementations, and that interfaces can be used to supplement the public visibility section of a class. A class using an interface in this way is said to implement the interface, and as a consequence must provide implementations for all of the methods the interface defines. We learned that variables may be defined as references to interfaces and can hold a pointer to any class implementing the interface, but that classes referenced by a variable defined as an interface reference are restricted to accessing through that variable only those members contributed by the interface. We also learned that polymorphism is always in effect when using interface reference variables for the simple reason that it is not possible to create an instance of an interface but only of a class implementing the interface. We learned that the use of interfaces provides a way to achieve the equivalent of multiple inheritance, and that their use promotes loose coupling between objects, alleviating the need for a component to necessarily know what type of class instance it is using.

Interfaces Exercises

Refer to Chapter 7 of the functional and technical requirements documentation (see Appendix B) for the accompanying ABAP exercise programs associated with this chapter. Take a break from reading the book at this point to reinforce what you have read by changing and executing the corresponding exercise programs. The exercise programs associated with this chapter are those in the 105 series: ZOOT105A through ZOOT105D.

Footnotes

1 It also is known as a “stand-alone interface.”

2 It is for this reason that I hesitate to include the definitions of variables in the set of components offered by an interface, since they would be publicly visible, hence modifiable by external entities. Although not technically prohibited, the inclusion of variables in interface definitions should be avoided by programmers not wanting to violate the principles of encapsulation.

3 The format of invoking a method as shown here is intended to be language independent, but closely resembles the format found with both Java and ABAP.

4 The attribute values shown for this entry represent those for the Navajo Generating Station near Page, Arizona, which consumes about 8 million tons of coal per year. Accordingly, its values shown for capacity in fuel unit and current level in fuel unit represent a 60-day and 30-day supply, respectively.

6 A case can be made that loose coupling also occurs when an instance of a subclass is referenced as an instance of one of its superclasses; however, such an arrangement depends on class inheritance and limits the flexibility to within the same inheritance hierarchy. By contrast, interfaces are not limited by such constraints.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset