In the previous exercise, you created a common superclass LCL_FLIGHT for the classes LCL_PASSENGER_FLIGHT and LCL_CARGO_FLIGHT. Now you will modify the local class LCL_CARRIER to utilize the inheritance relationship. You will type reference variables used as parameters to the type of the superclass and, instead of two separate instance attributes passenger_flights and cargo_flights, define a single instance attribute flights in which you can store references to all flight instances, regardless of whether they are passenger or cargo flights.
Task 1: Copy Template (Optional)
Copy the template class /LRN/CL_S4D401_OOS_INHERITANCE. If you finished the previous exercise, you can skip this task and continue editing your class ZCL_##_SOLUTION.
Steps
Copy class /LRN/CL_S4D401_OOS_INHERITANCE to a class in your own package (suggested name: ZCL_##_SOLUTION, where ## stands for your group number).
In the Project Explorer, right-click class /LRN/CL_S4D401_OOS_INHERITANCE to open the context menu.
From the context menu, choose Duplicate....
Enter the name of your package in the Package field. In the Name field, enter ZCL_##_SOLUTION, where ## stands for your group number.
Choose Next.
Confirm the transport request and choose Finish.
Activate the copy.
Press Ctrl + F3 to activate the class.
Task 2: Generic Parameter
In local class LCL_CARRIER, adjust the definitions of methods FIND_PASSENGER_FLIGHT and FIND_CARGO_FLIGHT. In both methods, type the exporting parameter e_flight as a reference variable based on local class LCL_FLIGHT.
Steps
In local class LCL_CARRIER, adjust the definition of method FIND_CARGO_FLIGHT. Type the returning parameter e_flight with LCL_FLIGHT instead of LCL_CARGO_FLIGHT. Make sure you save the change.
Adjust the code as follows:
123456789
METHODS find_cargo_flight
IMPORTING
i_airport_from_id TYPE /dmo/airport_from_id
i_airport_to_id TYPE /dmo/airport_to_id
i_from_date TYPE /dmo/flight_date
i_cargo TYPE /lrn/plane_actual_load
EXPORTING
e_flight TYPE REF TO lcl_flight
e_days_later TYPE i.
Analyze the use of the local variable flight in the implementation of the method FIND_CARGO_FLIGHT.
To display the type of the reference variable flight, place the cursor on the variable name and press F2.
Analyze the call of method FIND_CARGO_FLIGHT in method IF_OO_ADT_CLASSRUN~MAIN in your global class.
To display the type of the reference variable cargo_flight, place the cursor on the variable name and press F2.
Adjust the definition of method FIND_PASSENGER_FLIGHT in the same way. Type the returning parameter e_flight with LCL_FLIGHT instead of LCL_PASSENGER_FLIGHT.
Adjust the code as follows:
123456789
METHODS find_passenger_flight
IMPORTING
i_airport_from_id TYPE /dmo/airport_from_id
i_airport_to_id TYPE /dmo/airport_to_id
i_from_date TYPE /dmo/flight_date
i_seats TYPE i
EXPORTING
e_flight TYPE REF TO lcl_flight
e_days_later TYPE i.
Activate the code to verify that this change also does not cause any syntax errors.
Press Ctrl + F3 to activate the code.
Task 3: Generic Attribute
In local class LCL_CARRIER, define a private instance attribute flights in which you can store references to instances of LCL_PASSENGER_FLIGHT and LCL_CARGO_FLIGHT at the same time. Fill the attribute in the implementation of the CONSTRUCTOR method with the combined content of attributes passenger_flights and cargo_flights.
Steps
In local class LCL_FLIGHT, use a quick fix to generate a public table type that is based on this class (suggested name for the table type: tab).
Go to the definition of local class LCL_FLIGHT.
In the CLASS statement, place the cursor on lcl_flight and press Ctrl + 1 to invoke the available quick fixes.
From the list of available quick fixes, choose Generate table type for lcl_flight.
The new TYPES statement should look something like this:
1
TYPES tab TYPE STANDARD TABLE OF REF TO lcl_flight WITH DEFAULT KEY.
In the private section of local class LCL_CARRIER, define a new instance attribute flights. Type it with the table type that you just created in local class LCL_FLIGHT.
Adjust the code as follows:
1234
DATA passenger_flights TYPE lcl_passenger_flight=>tt_flights.
DATA cargo_flights TYPE lcl_cargo_flight=>tt_flights.
DATA flights TYPE lcl_flight=>tab.
Adjust the implementation of the CONSTRUCTOR method of local class LCL_CARRIER. After you called method GET_FLIGHTS_BY_CARRIER of LCL_PASSENGER_FLIGHT, add all object references stored in passenger_flights to flights.
Go to the implementation of the CONSTRUCTOR method in local class LCL_CARRIER.
Before the ENDMETHOD statement, add the following code:
123
LOOP AT passenger_flights INTO DATA(passflight).
APPEND passflight TO flights.
ENDLOOP.
If you prefer a table comprehension, add the following code instead:
12345
flights = VALUE #( BASE flights
FOR pflight IN passenger_flights (
pflight
)
).
Similarly, implement a loop over cargo_flights and add these references to flights as well.
Before the ENDMETHOD statement, add the following code:
123
LOOP AT cargo_flights INTO DATA(cargoflight).
APPEND cargoflight TO flights.
ENDLOOP.
If you prefer a table comprehension, add the following code instead:
12345
flights = VALUE #( BASE flights
FOR cflight IN cargo_flights (
cflight
)
).
Task 4: Generic Access and Down-Cast
Eliminate instance attributes passenger_flights and cargo_flights in local class LCL_CARRIER and replace them with the new attribute flights. Where the code accesses specific components of the subclasses, implement a down-cast.
Steps
In the definition part of local class LCL_CARRIER, remove or comment the definition of attributes passenger_flights and cargo_flights.
Select the two DATA statements and press Ctrl + < to add a comment sign in front of each code row:
In method CONSTRUCTOR, use inline declarations to declare passenger_flights and cargo_flights as local variables.
Adjust the code as follows:
1234567
DATA(passenger_flights) =
lcl_passenger_flight=>get_flights_by_carrier(
i_carrier_id = i_carrier_id ).
DATA(cargo_flights) =
lcl_cargo_flight=>get_flights_by_carrier(
i_carrier_id = i_carrier_id ).
After the method calls with the inline declarations, fill a private instance attribute with the number of rows in local variable passenger_flights (suggested name: pf_count).
Hint
First implement the value assignment. Then use a quick fix to create the attribute declaration.
Adjust the code as follows:
12345
DATA(passenger_flights) =
lcl_passenger_flight=>get_flights_by_carrier(
i_carrier_id = i_carrier_id ).
pf_count = lines( passenger_flights ).
Place the cursor on pf_count, press Ctrl + 1 and choose Declare attribute pf_count.
Similarly, fill a private instance attribute with the number of rows in local variable cargo_flights (suggested name: cf_count).
Adjust the code as follows:
12345
DATA(cargo_flights) =
lcl_cargo_flight=>get_flights_by_carrier(
i_carrier_id = i_carrier_id ).
cf_count = lines( cargo_flights ).
Place the cursor on cf_count, press Ctrl + 1 and choose Declare attribute cf_count.
In method GET_OUTPUT, replace the embedded LINES functions with the attributes you just defined.
Adjust the code as follows:
123456
METHOD get_output.
APPEND |{ 'Carrier Name:'(001) } { me->name }| TO r_result.
APPEND |{ 'Passenger Flights:'(002) } { pf_count }| TO r_result.
APPEND |{ 'Average free seats:'(003) } { get_average_free_seats( ) }| TO r_result.
APPEND |{ 'Cargo Flights:'(004) } { cf_count }| TO r_result.
ENDMETHOD.
In method FIND_CARGO_FLIGHT, replace attribute cargo_flights with attribute flights.
Adjust the code as follows:
12
LOOP AT me->flights INTO DATA(flight)
In the call of method GET_FREE_CAPACITY add a CAST expression.
Adjust the code as follows:
1234
IF connection_details-airport_from_id = i_airport_from_id
AND connection_details-airport_to_id = i_airport_to_id
AND CAST lcl_cargo_flight( flight )->get_free_capacity( ) >= i_cargo.
To make sure you only consider instances of LCL_CARGO_FLIGHT, extend the WHERE condition of the LOOP.
Hint
Remember that in internal tables with elementary row type you address the content with pseudo-component table_line.
Adjust the code as follows:
123
LOOP AT me->flights INTO DATA(flight)
WHERE table_line->flight_date >= i_from_date
AND table_line IS INSTANCE OF lcl_cargo_flight.
Adjust the implementation of method FIND_PASSENGER_FLIGHT in the same way.
Adjust the code as follows:
12345678910111213141516171819
LOOP AT me->flights INTO DATA(flight)
WHERE table_line->flight_date >= i_from_date
AND table_line IS INSTANCE OF lcl_passenger_flight.
DATA(connection_details) = flight->get_connection_details( ).
IF connection_details-airport_from_id = i_airport_from_id
AND connection_details-airport_to_id = i_airport_to_id
AND CAST lcl_passenger_flight( flight )->get_free_seats( ) >= i_seats.
DATA(days_later) = flight->flight_date - i_from_date.
IF days_later < e_days_later. e_flight = flight.
e_days_later = days_later.
ENDIF.
ENDIF.
ENDLOOP.
Adjust the implementation of the GET_AVERAGE_FREE_SEATS method. Use the internal table flights in the table reduction and add a CAST expression and a WHERE condition to the reduction. The required number of passenger flights is stored in the attribute pf_count created above.
Adjust the code as follows:
12345678910111213141516
METHOD get_average_free_seats.
r_result = REDUCE #(
INIT i = 0
FOR flight IN flights
WHERE ( table_line IS INSTANCE OF lcl_passenger_flight )
NEXT i += CAST lcl_passenger_flight( flight )->get_free_seats( )
) / pf_count.
ENDMETHOD.
Activate and test your global class as console app.
Press Ctrl + F3.
Press F9.