You introduced a common superclass LCL_FLIGHT for classes LCL_PASSENGER_FLIGHT and LCL_CARGO_FLIGHT. Now you adjust local class LCL_CARRIER to make use of the inheritance relation. You type parameters with a superclass reference and instead of two separate instance attributes passenger_flights and cargo_flights, you define a single instance attribute flights in which you can store the references to all flight instances, whether they are passenger flights or cargo flights.
Task 1: Copy Template (Optional)
Copy the template class. 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 view, 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 the name ZCL_##_SOLUTION, where ## stands for your group number.
Adjust the description and 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 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.
Adjust the code as follows:
1234567891011
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 implementation of method FIND_CARGO_FLIGHT.
To display the type of reference variable flight, place the cursor on the variable name and press F2.
Analyze the call method FIND_CARGO_FLIGHT in method IF_OO_ADT_CLASSRUN~MAIN in your global class.
To display the type of reference variable pass_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:
1234567891011
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 does also 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 quick fix.
From the list of available quick fixes, choose Generate table type for lcl_flight.
The new TYPES statement should look like this:
123
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 attribute flights. Type it with the table type that you just created in local class LCL_FLIGHT.
Adjust the code as follows:
123456
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. After you called method GET_FLIGHTS_BY_CARRIER of LCL_PASSENGER_PLANE, add all object references stored in passenger_flights to flights.
Go to the implementation of CONSTRUCTOR in local class LCL_CARRIER.
Before the ENDMETHOD statement, add the following code:
12345
LOOP AT passenger_flights INTO DATA(passflight).
APPEND passflight TO flights.
ENDLOOP.
If you prefer a table comprehension, add the following code:
12345678
flights = VALUE #( BASE flights
FOR pflight IN passenger_flights
( pflight )
).
Similarly, implement a loop over cargo_flights and add these references to flights, too.
Before the ENDMETHOD statement, add the following code:
12345
LOOP AT cargo_flights INTO DATA(cargoflight).
APPEND cargoflight TO flights.
ENDLOOP.
If you prefer a table comprehension, add the following code:
123456
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 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:
123456789
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:
1234567
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:
1234567
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:
12345678910
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:
1234
* LOOP AT me->cargo_flights INTO DATA(flight)
LOOP AT me->flights INTO DATA(flight)
In the call of method GET_FREE_CAPACITY add a CAST expression.
Adjust the code as follows:
1234567
IF connection_details-airport_from_id = i_airport_from_id
AND connection_details-airport_to_id = i_airport_to_id
* AND flight->get_free_capacity( ) >= i_cargo.
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:
12345
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:
12345678910111213141516171819202122
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. "earlier than previous one?
e_flight = flight.
e_days_later = days_later.
ENDIF.
ENDIF.
ENDLOOP.
Adjust the implementation of the GET_AVERAGE_FEE_SEATS method. Add a CAST expression and a WHERE condition to the table reduction.
Adjust the code as follows:
12345678910111213141516171819202122
METHOD get_average_free_seats.
* Table Reductions
**********************************************************************
* r_result = REDUCE #(
* INIT i = 0
* FOR <flight> IN passenger_flights
* NEXT i += <flight>->get_free_seats( )
* ) / lines( passenger_flights ) .
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.