As shown here, lcl_vehicle is a superclass; and lcl_car, lcl_truck, and lcl_bus are subclasses of the superclass. All the common properties of these subclasses are defined and implemented in the superclass. Therefore, from the perspective of a superclass, each subclass is a special part of a superclass containing properties that are both common as well as specific to it.
Specialization is often described as an “is a” relationship. In this example, you can say that “A truck is a specific vehicle.”
However, if we look at the same relationship from the perspective of a subclass, it is termed as generalization. This is because all subclasses contain the common properties defined in the superclass.
CHARACTERISTIC OF GENERALIZATION / SPECIALIZATION
Generalization or specialization offers an improved structure to the software, as commonly used elements are stored only once in a central location known as superclass. Components in a superclass are then automatically available to all the subclasses. You must know how to implement a superclass in order to determine whether the inherited components from the superclass are sufficient for the subclass, or if they need to be extended.
However, subclasses can be extended or changed as per the requirement.
Thus, there are very strong links between the superclass and the subclass, which are dependent on the superclass.
INHERITANCE - SYNTAX
Inheritance relationship is defined syntactically using the INHERITING FROM addition in the definition of a subclass, followed by the superclass name as shown in the slide. Superclass definition is the prerequisite for an inheritance relationship to be established. A subclass can access some of the properties of a superclass through inheritance. In this example, the subclass lcl_truck will also contain the superclass method set_type.
REDEFINING METHOD
Keyword REDEFINITION is used when the inherited methods from the superclass needs to be extended. However, the signature of the inherited method should not change.
If the keyword REDEFINITION is used, a new implementation part for that method must be specified. As shown here, in a redefined method’s implementation part, the keyword “super” can be used to access the components of the superclass.
As shown in the slide, the class lcl_bus and class lcl_truck both contain the method display_attributes; but the output of the method is different. Most importantly, the semantics of the method have not changed.
Constructors in inheritance do not follow the same rules as the other instance methods when they are redefined. The constructor of the superclass can be used as it is or changed in the subclass, which means that the signature of the constructor can change.
However, it is compulsory to call the superclass constructor during its implementation in subclass.
Let us look at the classes: lcl_1, lcl_2, and lcl_3. Objects go_2 and go_3 refer to the classes lcl_2 and lcl_3, respectively as shown. The class lcl_3 has a constructor with two parameters. Values to the constructor parameters can be supplied directly through the object as shown in case 1. However, if the constructor is an inherited one as in case 2, then you need to search the superclass constructor in the hierarchy. Subsequently, the values are supplied to the parameters.
The visibility of the components of a class, which was restricted to Public or Private, is extended using inheritance. We now have protected components whose visibility lies between public and private. Components that are categorized as protected are visible to the class and all its subclasses.
However, when local classes are defined, the syntactical sequence followed for the visibility sections is: PUBLIC SECTION, PROTECTED SECTION, and PRIVATE SECTION.
We already know that the public components of a class can be accessed from outside; whereas the private components can only be accessed from within the class. Consider the class lcl_bus which inherits from the superclass lcl_vehicle. Here, mv_make and mv_model are private attributes of the class. Although they are inherited, they cannot be accessed directly. Therefore, lcl_bus only has public methods, constructor and display_attributes, as well as the protected attribute mv_color. These can only be accessed from inside.
All subclasses of a superclass can access its public or protected static attributes.
Redefinition of static methods is not possible.
When the superclass or one of its subclasses is accessed for the first time, the static constructor of a superclass is executed.
A subclass can define a static constructor of its own irrespective of whether the superclass has one or not.
If both subclass and superclass contain a static constructor, then both will be executed whenever the class is accessed for the first time.
Let us say that the class lcl_truck is a subclass of the superclass lcl_vehicle. Object reference variables to both the classes are defined using the data statement. Using the statement go_vehicle = go_truck, we are assigning an object reference of type subclass to a superclass reference variable. After assignment, go_vehicle can access the inherited components in the subclass as shown. This is up-cast or widening cast.
STATIC AND DYNAMIC TYPE OF REFERENCES
The statement DATA go_vehicle TYPE REF TO lcl_vehicle creates a static reference variable. So a static reference variable
is defined using the TYPE REF TO addition;
remains same throughout; and
specifies what attributes and methods can be accessed.
On the other hand, go_vehicle in the second diagram is a dynamic reference variable which
is created by assignment;
can change during the execution of a program; and
specifies which attributes and methods can be implemented.
With the help of cast assignments, generic access to the subclass components by a reference variable of type superclass is possible.
When a user is not at all interested in the finer points of the instances of the subclasses but simply wants to address the shared components, the user can make use of a superclass reference for this access.
When a user is not at all interested in the finer points of the instances of the subclasses but simply wants to address the shared components, the user can make use of a superclass reference for this access.
In this example, objects of different classes, lcl_bus, lcl_truck, and lcl_car, have references of type superclass lcl_rental. Here, it is possible to store all these object references in an internal table.
This slide explains that up-cast assignment occurs when the vehicle reference is passed to the formal parameter of the add_vehicle method. Shared components can be accessed using the loop at the internal table containing all the vehicle references.
The output of the method display_attributes depends on the object to which the superclass reference variable – go_vehicle – points. As shown in the slide, the output of the method display_attributes is different in the two method calls.
As shown here, gt_vehicles is a collection of vehicles in an internal table. The CALL FUNCTION statement inside the loop displays the properties of individual objects. This can also be done using a function group which contains different function modules.
In this example, the superclass reference variable go_vehicle is assigned to the subclass reference go_truck2. After this assignment, go_truck2 can access all the public components of lcl_truck as shown. This is defined as narrowing cast or down cast. The down-cast operator (?=) used in the process is shown in the example.
All vehicle reference types are stored in an internal table that is typed as lcl_vehicle. You require down-cast assignment to address specific components of instances. It is also needed for keeping references of these instances in variables which are typed on the superclass.
In down-cast assignment, if the static target reference is not type compatible with the source reference, exceptions can be raised. As shown in this example, the exception class – cx_sy_move_cast_error – which can raise the exception is caught using the CATCH statement within the TRY-ENDTRY block.
If a generalization or specialization relationship is observed between certain classes, then inheritance can be used to represent this in ABAP Objects. There are various advantages of linking classes through inheritance concept:
It allows for centralized maintenance.
It enables safe and generic method of access.The software component can be easily extended.
It allows for centralized maintenance.
It enables safe and generic method of access.The software component can be easily extended.
If the concept of “is a (specific)” is not understood properly, then the direction of inheritance could be easily misunderstood, which can be risky. For example, the class, car, has two subclasses, red and blue.
The statement “A red car is a specific car” may seem correct initially. This means every car must have the attribute Color, assuming that it is relevant to the application. Thus, the attribute has to be predefined in the superclass; otherwise, the authorizations for subclasses of this type are no longer possible. This may sound contradictory in a real life scenario.
CENTRAL DEFINITION OF SHARED COMPONENTS
An interface can simply be defined as a superclass that cannot be instantiated. This means that they do not have an implementation part. All the components of an interface are public. In ABAP Objects, the components which are defined in a superclass can be defined with interfaces. Let us look at an example to understand this.
As shown in the example here, the interface can be suitably modeled to provide appropriate services to the classes, lcl_carrier, lcl_hotel, and lcl_rental.
THE CLIENT DEFINES A PROTOCOL
Interfaces are like superclasses that do not have an implementation of their own. In an interface, a client defines the services that they expect different classes to perform. Each class can now decide whether it needs to implement the interface. This is similar to the specialization relationship with the superclass.
INTERFACE IN UML NOTATION
Interfaces are represented in the same way as classes in a UML notation. The name of the interface also contains the stereotype “«interface»” addition, which is optional. The use of an interface is shown by a dotted line with a two-sided arrow pointing from the user to the interface. A class implementing an interface is represented by a dotted arrow from the class to the interface.
DEFINING AND IMPLEMENTING INTERFACE
An interface is defined using the keyword INTERFACE followed by its name. Here, the interface contains a method display_partner. An interface does not have different visibility sections like classes. Therefore, all the components of an interface are public in nature. An interface is called in the method definition using the keyword INTERFACES, as shown. After the interface call, the methods of the interface can be implemented in the class definition. Interface method is implemented using the syntax, interface name, ‘tilde’ operator, followed by the method name, as shown. The tilde operator is also known as the interface resolution operator.
ADDRESING INTERFACE COMPONENT USING OBJECT REFERENCES
As shown in the slide, class lcl_rental implements the interface lif_partner. This interface (lif_partner) contains two methods, display_partner and check_availability. Components of an interface can only be accessed using an object reference of the class which implements the interface. Here, go_rental is the object reference of the class lcl_rental. The interface method can be called using the syntax, go_renta → lif_partner~display_partner ( ).
UP-CAST WITH INTERFACE REFERENCES
The class – lcl_rental – implements the interface – lif_partner – and can therefore access the methods of the interface. We have reference variables go_rental and go_partner of type class and interface, respectively. The object reference – go_rental – created using the data statement can access the public components of the class. When this object reference is assigned to a reference variable of type interface, interface reference variable can also access the interface components. This is up-cast using interfaces. However, after assignment, go_partner can only access the interface components.
ROW TYPE OF THE INTERNAL TABLE IN THE APPLICATION EXAMPLE
This slide depicts different classes, lcl_hotel, lcl_rental, and lcl_carrier, all of which refer to lcl_travel_agency. The objects of these different classes can be managed using an internal table of type lif_partner.
The components of the interface can be accessed uniformly using the method – add_partner – as its parameter is already typed as a reference to the interface.
POLYMORPHISM - GENERIC ACCESS USING THE INTERFACE REFERENCE
Interface references can be used to call methods, which give different outputs based on the object reference they point to. In this example, the implemented method – display_partner – displays different output depending on the object reference it refers to dynamically.
DOWN-CAST ASSIGNMENT AND EXCEPTION HANDLING IN THE APPLICATION EXAMPLE
At runtime, interface reference variables can point to instances of the implementing class. After this type of assignment, where a reference variable points back to a reference of the implementing class, access is not limited to the interface components. As shown here, all components of the lcl_carrier instance can be re-accessed after the assignment using reference r_carrier.
INTERFACE HIERARCHY IN THE APPLICATION EXAMPLE
Let us understand the extension of interfaces using this example. As shown here, both lcl_motel and lcl_hotel implement the interface, and request for a particular service which must be included in the interface. It cannot be defined individually for both. However, it should also be noted that there are several other objects already referring to the interface. Hence, it is a matter of debate whether an extension of this kind is appropriate.
COMPOUND INTERFACE IN UML NOTATION
This slide illustrates two interfaces, lif_partner and lif_lodging. As we all know, interfaces can include other interfaces. The including interface is known as a compound interface. The included interface is represented as a component of another interface and is, therefore, known as a component interface.
DEFINITION AND IMPLEMENTATION OF COMPOUND INTERFACE : SYNTAX
In this example, interface – lif_partner – is a component interface, and therefore, it is defined first. This interface is included or called in another interface – lif_lodging – using INTERFACES statement. Thus, the interface – lif_lodging – is now a compound interface. Class lcl_hotel implements the interface – lif_lodging. As it is a compound interface, lcl_hotel can also access display_partner, which is a method in the component interface. This is similar to how it can access method – book_room – in compound interface.
ADDRESSING COMPONENT IN COMPOUND INTERFACE - SYNTAX
Up-cast and down-cast assignments are possible with compound interfaces. In case of up-cast, after the cast assignment occurs, go_lodging can call the methods, display_partner and book_room. Similarly, go_partner can call display_partner method as shown. In the same way, specific methods can be accessed using down-cast assignment.
USING INTERFACE
When generalization or specialization relationships are created using an interface, it can help in
defining protocol and services separately;
allowing safe and generic method of access; and
realizing multiple inheritances.
What all this means is that, the software can be extended easily.
EVENT-CONROLLED METHOD CLASS
Events, like attributes and methods, are components of a class. Events are of two types: Instance events and Static events. Instance events are triggered by the instances of the class, while static events are triggered by the class itself.
Whenever an event is triggered at runtime, the system calls for handler methods to respond to the event call.
In this example, creation of an instance in the “vehicle” class triggers the event “vehicle created.” This event is processed differently by different instances. For example, the car rental company considers purchasing a vehicle, while the vehicle registration office registers the car.
EVENT HANDLING IN A UML CLASS DIAGRAM
In UML notation, events are represented by a dotted arrow with the stereotype «handlesEventOf» pointing from the handling class to the triggering class. In the example shown here, lcl_rental is the handling class which handles the event – vehicle_created – triggered in raising class lcl_vehicle. The definition and signature of the event are defined in the handler method inside the handling class.
TRIGERING AND HANDLING EVENT - OVERVIEW
Instance events are defined with the keyword EVENTS; while static events are defined using the keyword CLASS-EVENTS. Objects of a class or the class itself can trigger the event using the RAISE EVENT statement. Once an event is triggered, it has to be handled. To handle a raised event, we can make use of a handler method of the handler class using the methods...FOR EVENT … OF …statement as shown; or by using a handler object with the SET HANDLER statement.
DEFINING AND TRIGERING EVENTS - SYNTAX
Instance events are defined using the EVENTS statement; while static events are defined using the CLASS-EVENTS statement. The signature of events can only have exporting parameters, which must be passed by value. A class or instance can trigger an event at runtime using the RAISE EVENT statement as shown.
Instance methods can trigger both instance events and static events; whereas static methods can only trigger static events.
HANDLING EVENTS - SYNTAX
Event handling by the instance or static method within a class requires FOR EVENT addition with the event name, along with the OF addition with the class or interface name. If the event has exporting parameters, then in order to pass values to these, you need to specify exporting parameters immediately after the keyword IMPORTING in the method definition.
In addition to the explicitly defined exporting parameters, the predefined importing parameter, sender, can always be listed. Using this parameter, you can place a reference to the event-trigger object into the handler method.
REGISTERING EVENT HANDLING
When an event is raised, it must be handled appropriately by a handler method. There can be many events which may be triggered. The handler method determines which event of which class method will react, and how it will react. At runtime, the system also determines which possible reactions will take place and at what time.
These specifications are collectively referred to as registration. It is always carried out using the trigger. The runtime makes use of the registrations of the trigger to determine which event handler methods need to be called.
REGISTERING EVENT HANDLING - SYNTAX
Events are only registered during the program runtime using the SET HANDLER statement. Syntactically in instance events, FOR addition is followed by the reference to the object that triggers the event. The addition – ACTIVATION 'X' – is optional during registration. Several methods can be registered with one SET HANDLER statement.
REGISTRATION/DEREGISTRATION: HANDLER TABLES
All events defined by an object or a class are stored in an internal table, also known as the handler table. This example shows handler table for two instances, ‘bus1’ and ‘bus2.’ All handler methods registered to the various events are listed within the table. The handler table also contains references to the registered objects in case of instance methods.
EVENTS: VISIBILITY SECTION
Events and event handler methods can be categorized as public, protected, or private on the basis of their visibility.
The visibility of an event determines where the event can be handled:
PUBLIC events can be handled outside.
PROTECTED events can only be handled within that class or its subclasses.
PRIVATE events can only be handled within its class.
The visibility of a handler method determines the locations where the SET HANDLER statement can be programmed.
If the handler is defined in PUBLIC SECTION, the SET HANDLER statement can appear anywhere in the program.
If the handler is defined in PROTECTED SECTION, the SET HANDLER statement can appear within that class or its subclasses.
If the handler is defined in PRIVATE SECTION, the SET HANDLER statement can only appear within its class.
An interface can simply be defined as a superclass that cannot be instantiated. This means that they do not have an implementation part. All the components of an interface are public. In ABAP Objects, the components which are defined in a superclass can be defined with interfaces. Let us look at an example to understand this.
As shown in the example here, the interface can be suitably modeled to provide appropriate services to the classes, lcl_carrier, lcl_hotel, and lcl_rental.
Interfaces are like superclasses that do not have an implementation of their own. In an interface, a client defines the services that they expect different classes to perform. Each class can now decide whether it needs to implement the interface. This is similar to the specialization relationship with the superclass.
Interfaces are represented in the same way as classes in a UML notation. The name of the interface also contains the stereotype “«interface»” addition, which is optional. The use of an interface is shown by a dotted line with a two-sided arrow pointing from the user to the interface. A class implementing an interface is represented by a dotted arrow from the class to the interface.
An interface is defined using the keyword INTERFACE followed by its name. Here, the interface contains a method display_partner. An interface does not have different visibility sections like classes. Therefore, all the components of an interface are public in nature. An interface is called in the method definition using the keyword INTERFACES, as shown. After the interface call, the methods of the interface can be implemented in the class definition. Interface method is implemented using the syntax, interface name, ‘tilde’ operator, followed by the method name, as shown. The tilde operator is also known as the interface resolution operator.
ADDRESING INTERFACE COMPONENT USING OBJECT REFERENCES
As shown in the slide, class lcl_rental implements the interface lif_partner. This interface (lif_partner) contains two methods, display_partner and check_availability. Components of an interface can only be accessed using an object reference of the class which implements the interface. Here, go_rental is the object reference of the class lcl_rental. The interface method can be called using the syntax, go_renta → lif_partner~display_partner ( ).
The class – lcl_rental – implements the interface – lif_partner – and can therefore access the methods of the interface. We have reference variables go_rental and go_partner of type class and interface, respectively. The object reference – go_rental – created using the data statement can access the public components of the class. When this object reference is assigned to a reference variable of type interface, interface reference variable can also access the interface components. This is up-cast using interfaces. However, after assignment, go_partner can only access the interface components.
This slide depicts different classes, lcl_hotel, lcl_rental, and lcl_carrier, all of which refer to lcl_travel_agency. The objects of these different classes can be managed using an internal table of type lif_partner.
The components of the interface can be accessed uniformly using the method – add_partner – as its parameter is already typed as a reference to the interface.
Interface references can be used to call methods, which give different outputs based on the object reference they point to. In this example, the implemented method – display_partner – displays different output depending on the object reference it refers to dynamically.
At runtime, interface reference variables can point to instances of the implementing class. After this type of assignment, where a reference variable points back to a reference of the implementing class, access is not limited to the interface components. As shown here, all components of the lcl_carrier instance can be re-accessed after the assignment using reference r_carrier.
Let us understand the extension of interfaces using this example. As shown here, both lcl_motel and lcl_hotel implement the interface, and request for a particular service which must be included in the interface. It cannot be defined individually for both. However, it should also be noted that there are several other objects already referring to the interface. Hence, it is a matter of debate whether an extension of this kind is appropriate.
This slide illustrates two interfaces, lif_partner and lif_lodging. As we all know, interfaces can include other interfaces. The including interface is known as a compound interface. The included interface is represented as a component of another interface and is, therefore, known as a component interface.
In this example, interface – lif_partner – is a component interface, and therefore, it is defined first. This interface is included or called in another interface – lif_lodging – using INTERFACES statement. Thus, the interface – lif_lodging – is now a compound interface. Class lcl_hotel implements the interface – lif_lodging. As it is a compound interface, lcl_hotel can also access display_partner, which is a method in the component interface. This is similar to how it can access method – book_room – in compound interface.
Up-cast and down-cast assignments are possible with compound interfaces. In case of up-cast, after the cast assignment occurs, go_lodging can call the methods, display_partner and book_room. Similarly, go_partner can call display_partner method as shown. In the same way, specific methods can be accessed using down-cast assignment.
When generalization or specialization relationships are created using an interface, it can help in
defining protocol and services separately;
allowing safe and generic method of access; and
realizing multiple inheritances.
What all this means is that, the software can be extended easily.
Events, like attributes and methods, are components of a class. Events are of two types: Instance events and Static events. Instance events are triggered by the instances of the class, while static events are triggered by the class itself.
Whenever an event is triggered at runtime, the system calls for handler methods to respond to the event call.
In this example, creation of an instance in the “vehicle” class triggers the event “vehicle created.” This event is processed differently by different instances. For example, the car rental company considers purchasing a vehicle, while the vehicle registration office registers the car.
In UML notation, events are represented by a dotted arrow with the stereotype «handlesEventOf» pointing from the handling class to the triggering class. In the example shown here, lcl_rental is the handling class which handles the event – vehicle_created – triggered in raising class lcl_vehicle. The definition and signature of the event are defined in the handler method inside the handling class.
Instance events are defined with the keyword EVENTS; while static events are defined using the keyword CLASS-EVENTS. Objects of a class or the class itself can trigger the event using the RAISE EVENT statement. Once an event is triggered, it has to be handled. To handle a raised event, we can make use of a handler method of the handler class using the methods...FOR EVENT … OF …statement as shown; or by using a handler object with the SET HANDLER statement.
Instance events are defined using the EVENTS statement; while static events are defined using the CLASS-EVENTS statement. The signature of events can only have exporting parameters, which must be passed by value. A class or instance can trigger an event at runtime using the RAISE EVENT statement as shown.
Instance methods can trigger both instance events and static events; whereas static methods can only trigger static events.
Event handling by the instance or static method within a class requires FOR EVENT addition with the event name, along with the OF addition with the class or interface name. If the event has exporting parameters, then in order to pass values to these, you need to specify exporting parameters immediately after the keyword IMPORTING in the method definition.
In addition to the explicitly defined exporting parameters, the predefined importing parameter, sender, can always be listed. Using this parameter, you can place a reference to the event-trigger object into the handler method.
When an event is raised, it must be handled appropriately by a handler method. There can be many events which may be triggered. The handler method determines which event of which class method will react, and how it will react. At runtime, the system also determines which possible reactions will take place and at what time.
These specifications are collectively referred to as registration. It is always carried out using the trigger. The runtime makes use of the registrations of the trigger to determine which event handler methods need to be called.
Events are only registered during the program runtime using the SET HANDLER statement. Syntactically in instance events, FOR addition is followed by the reference to the object that triggers the event. The addition – ACTIVATION 'X' – is optional during registration. Several methods can be registered with one SET HANDLER statement.
All events defined by an object or a class are stored in an internal table, also known as the handler table. This example shows handler table for two instances, ‘bus1’ and ‘bus2.’ All handler methods registered to the various events are listed within the table. The handler table also contains references to the registered objects in case of instance methods.
Events and event handler methods can be categorized as public, protected, or private on the basis of their visibility.
The visibility of an event determines where the event can be handled:
PUBLIC events can be handled outside.
PROTECTED events can only be handled within that class or its subclasses.
PRIVATE events can only be handled within its class.
The visibility of a handler method determines the locations where the SET HANDLER statement can be programmed.
If the handler is defined in PUBLIC SECTION, the SET HANDLER statement can appear anywhere in the program.
If the handler is defined in PROTECTED SECTION, the SET HANDLER statement can appear within that class or its subclasses.
If the handler is defined in PRIVATE SECTION, the SET HANDLER statement can only appear within its class.