Professional Documents
Culture Documents
Techniques
Applies to:
All SAP Systems supporting object oriented programming. For more information, visit the ABAP homepage.
Summary
This tutorial explains the Code Refactoring Techniques based on example programs written in ABAP Objects
Author Bio
Sukru Ilkel Birakoglu is working as Senior Support Consultant in SAP Labs France. He is
developing in field of ECATT Test Tools at the moment.
Table of Contents
1. Consolidate Duplicate Conditional Fragments ...............................................................................................3
2. Preserve whole object for method calls..........................................................................................................4
3. Decompose Conditional..................................................................................................................................8
4. Extract Method..............................................................................................................................................11
5. Introduce Explaining Variable.......................................................................................................................19
6. Split Temporary Variable ..............................................................................................................................22
7. Self Encapsulate Attributes of a Class .........................................................................................................23
8. Replace Literals and Numbers in Code with Constants ...............................................................................27
9. Replace Type Codes with Subclasses .........................................................................................................29
10. Introduce Null Object ..................................................................................................................................35
11. Separate Query and Modifier Methods.......................................................................................................42
12. Parameterize Method .................................................................................................................................45
13. Pull up Field in the Class Hierarchy............................................................................................................49
14. Pull up Method in the Class Hierarchy .......................................................................................................53
Copyright...........................................................................................................................................................56
REPORT zsb_dupl_cond_fragments.
WRITE gv_discount.
In this refactoring, the common code fragment WRITE gv_discount. is moved outside the conditional
expression.
REPORT zsb_preserve_whole_object.
*----------------------------------------------------------------------*
* CLASS lcl_order DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_order DEFINITION.
PUBLIC SECTION.
METHODS : constructor
IMPORTING
iv_id TYPE char5
iv_material_id TYPE char10
iv_quantity TYPE i
iv_unit TYPE char3
iv_unit_price TYPE i.
*----------------------------------------------------------------------*
* CLASS lcl_order_collector DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_order_collector DEFINITION.
PUBLIC SECTION.
CLASS-METHODS : write_total_order_price
IMPORTING
iv_id TYPE char5
iv_material_id TYPE char10
iv_quantity TYPE i
iv_unit TYPE char3
iv_unit_price TYPE i.
*----------------------------------------------------------------------*
* CLASS lcl_order IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_order IMPLEMENTATION.
METHOD constructor.
mv_id = iv_id.
mv_material_id = iv_material_id.
mv_unit = iv_unit.
mv_unit_price = iv_unit_price.
mv_quantity = iv_quantity.
ENDMETHOD. "constructor
ENDCLASS. "lcl_order IMPLEMENTATION
*----------------------------------------------------------------------*
* CLASS lcl_order_collector IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_order_collector IMPLEMENTATION.
METHOD write_total_order_price.
ENDMETHOD. "write_total_order_price
ENDCLASS. "lcl_order_collector IMPLEMENTATION
START-OF-SELECTION.
lcl_order_collector=>write_total_order_price(
EXPORTING
iv_id = go_order->mv_id
iv_material_id = go_order->mv_material_id
iv_quantity = go_order->mv_quantity
iv_unit = go_order->mv_unit
iv_unit_price = go_order->mv_unit_price ).
*----------------------------------------------------------------------*
* CLASS lcl_order_collector DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_order_collector DEFINITION.
PUBLIC SECTION.
CLASS-METHODS : write_total_order_price
IMPORTING
io_order type ref to lcl_order.
*----------------------------------------------------------------------*
* CLASS lcl_order IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_order IMPLEMENTATION.
METHOD constructor.
mv_id = iv_id.
mv_material_id = iv_material_id.
mv_unit = iv_unit.
mv_unit_price = iv_unit_price.
mv_quantity = iv_quantity.
ENDMETHOD. "constructor
ENDCLASS. "lcl_order IMPLEMENTATION
*----------------------------------------------------------------------*
* CLASS lcl_order_collector IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_order_collector IMPLEMENTATION.
METHOD write_total_order_price.
ENDMETHOD. "write_total_order_price
ENDCLASS. "lcl_order_collector IMPLEMENTATION
START-OF-SELECTION.
lcl_order_collector=>write_total_order_price(
EXPORTING
io_order = go_order ).
3. Decompose Conditional
Explanation: If complicated operations are executed on each branch of a conditional statement,
encapsulate these operations in separate methods
Motivation:
• Increases the readability and maintainablity of the code
• Groups complicated operations in separate logical units
• Keeps the code from deep if..else statements which makes the code error prone
Steps of Refactoring:
• Find out the conditional expressions in your code which have many complicated operations in each
branch
• Create one or more methods which encapsulate these operations
Example Code Fragment:
Code Before Code Refactoring
*&---------------------------------------------------------------------*
*& Report ZSB_DECOMPOSE_CONDITIONAL
*&
*&---------------------------------------------------------------------*
*&
*&
*&---------------------------------------------------------------------*
REPORT zsb_decompose_conditional.
IF gv_customer_1 EQ gc_person.
IF gv_product_price > 8.
gv_reduction = gv_product_price * '0.1'.
ELSE.
gv_reduction = gv_product_price * '0.05'.
ENDIF.
ELSEIF gv_customer_1 EQ gc_company.
IF gv_product_price > 6.
gv_reduction = gv_product_price * '0.2'.
ELSE.
gv_reduction = gv_product_price * '0.15'.
ENDIF.
ENDIF.
WRITE / gv_reduction.
REPORT zsb_decompose_conditional.
*----------------------------------------------------------------------*
* CLASS lcl_reduction_calculator DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_reduction_calculator DEFINITION.
PUBLIC SECTION.
CLASS-METHODS : get_person_reduction
IMPORTING
iv_product_price TYPE i
RETURNING value(rv_reduction)
TYPE gty_decimal,
get_company_reduction
IMPORTING
iv_product_price TYPE i
RETURNING value(rv_reduction)
TYPE gty_decimal.
*----------------------------------------------------------------------*
* CLASS lcl_reduction_calculator IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_reduction_calculator IMPLEMENTATION.
METHOD get_person_reduction.
IF iv_product_price > 8.
rv_reduction = iv_product_price * '0.1'.
ELSE.
rv_reduction = iv_product_price * '0.05'.
ENDIF.
ENDMETHOD. "get_person_reduction
METHOD get_company_reduction.
IF iv_product_price > 6.
rv_reduction = iv_product_price * '0.2'.
ELSE.
rv_reduction = iv_product_price * '0.15'.
ENDIF.
ENDMETHOD. "get_company_reduction
ENDCLASS. "lcl_reduction_calculator IMPLEMENTATION
START-OF-SELECTION.
IF gv_customer_1 EQ gc_person.
gv_reduction = lcl_reduction_calculator=>get_person_reduction(
gv_product_price ).
ELSEIF gv_customer_1 EQ gc_company.
gv_reduction = lcl_reduction_calculator=>get_person_reduction(
gv_product_price ).
ENDIF.
WRITE / gv_reduction.
4. Extract Method
Explanation : If the code in the body of a method is too long, you use too many local variables in the
method and you have long comments for certain code fragments in the code, turn that fragment of code into
its own method
Motivation:
• Increases the readability of higher level and client methods using this code.
• The code fragment turned into a method can be reused
• Code fragments which are turned into a method can be overridden in a subclass if overriding is
foreseen for this fragment of code
Steps of Refactoring:
• Find out the code fragments which can be encapsulated into new methods
• Create ea new method with an explanatory name and copy the code fragment into the body of the
newly created method
• The parameters and local variables of the new method consist of the local variables referenced in
the old code fragment. Create the parameters and the local variables of the new method based on
this information.
Example Code Fragment:
Code Before Code Refactoring
REPORT zsb_extract_method.
*----------------------------------------------------------------------*
* CLASS lcl_bank DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_bank DEFINITION.
PUBLIC SECTION.
*----------------------------------------------------------------------*
* CLASS lcl_bank IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_bank IMPLEMENTATION.
METHOD calculate_interest.
ENDMETHOD. "calculate_interest
ENDCLASS. "lcl_bank IMPLEMENTATION
START-OF-SELECTION.
gv_interest_amount = lcl_bank=>calculate_interest(
iv_capital_amount = 100
iv_interest_rate = 5
iv_no_of_months = 4
).
*----------------------------------------------------------------------*
* CLASS lcl_bank DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_bank DEFINITION.
PUBLIC SECTION.
ty_interest.
PRIVATE SECTION.
CLASS-METHODS write_header
IMPORTING
iv_capital_amount TYPE i
iv_interest_rate TYPE i
iv_no_of_months TYPE i
.
CLASS-METHODS calculate_interest_amount
IMPORTING
iv_capital_amount TYPE i
iv_interest_rate TYPE i
iv_no_of_months TYPE i
CHANGING
cv_interest_amount TYPE ty_interest
.
CLASS-METHODS write_footer
IMPORTING
iv_interest_amount TYPE ty_interest.
ENDCLASS. "lcl_bank DEFINITION
*----------------------------------------------------------------------*
* CLASS lcl_bank IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_bank IMPLEMENTATION.
METHOD write_footer.
ULINE.
WRITE :/ 'Interest amount is calculated for:', sy-uname.
WRITE :/ 'Calculated interest amount :', iv_interest_amount.
ENDMETHOD. "write_footer
METHOD write_header .
WRITE / 'Calculating interest'.
ULINE.
WRITE: / 'Capital Amount:', iv_capital_amount.
WRITE: / 'Interest Rate in Percent:', iv_interest_rate.
WRITE: / 'Number of months :', iv_no_of_months.
ENDMETHOD. "write_header
METHOD calculate_interest_amount .
DATA lv_interest_amount TYPE ty_interest .
DATA lv_interest_in_percent TYPE ty_interest .
DATA lv_last_capital TYPE ty_interest .
lv_last_capital = iv_capital_amount.
DO iv_no_of_months TIMES.
lv_interest_amount = lv_last_capital * lv_interest_in_percent.
lv_last_capital = lv_last_capital + lv_interest_amount.
ADD lv_interest_amount TO cv_interest_amount.
ENDDO.
ENDMETHOD. "calculate_interest_amount
METHOD calculate_interest.
ENDMETHOD. "calculate_interest
ENDCLASS. "lcl_bank IMPLEMENTATION
START-OF-SELECTION.
gv_interest_amount = lcl_bank=>calculate_interest(
iv_capital_amount = 100
iv_interest_rate = 5
iv_no_of_months = 4
).
Step 2: The refactoring wizard appears on the screen. Press continue button on the first screen of the
wizard
Step 3: In the next screen of the refactoring assistant , enter the name of the method which will be added to
the class and have the code fragment we selected as its body. You can also select the visibility area of the
class to which the method will be added
Step 4: Check the data on the screen and press the Continue button to finish the code refactoring
The new method WRITE_HEADER is added to the private section of class LCL_BANK by the refactoring
assistant as below
The code fragment in the method CALCULATE_INTEREST which is selected for extraction is replaced by
the call of new method WRITE_HEADER
Step 5: After you create methods for all code fragments you want to extract some local variables of the
method CALCULATE_INTEREST becomes obsolete. These obsolete variables can aslo be deleted
automatically using the refactoring assistant. Right click the mouse button in the body of the method of
which useless local variables and follow the path Refactoring->Delete Unused Data Declarations.
As a result, the local variables lv_last_capital, lv_interest_in_percent and lv_interest_amount are deleted in
method CALCULATE_INTEREST.
*----------------------------------------------------------------------*
* CLASS lcl_price_calculator DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_price_calculator DEFINITION.
PUBLIC SECTION.
CLASS-METHODS : calculate_total_price
IMPORTING
iv_product_name TYPE string
iv_no_of_products TYPE i
iv_customer_type TYPE string
EXPORTING
ev_total_price TYPE p.
BEGIN OF c_customer_type,
frequent TYPE string VALUE 'FREQUENT',
rare TYPE string VALUE 'RARE',
first_time TYPE string VALUE 'FIRST_TIME',
normal TYPE string VALUE 'NORMAL',
END OF c_customer_type.
*----------------------------------------------------------------------*
* CLASS lcl_price_calculator IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
ENDIF.
ENDMETHOD. "calculate_total_price
ENDCLASS. "lcl_price_calculator IMPLEMENTATION
BEGIN OF c_customer_type,
frequent TYPE string VALUE 'FREQUENT',
rare TYPE string VALUE 'RARE',
first_time TYPE string VALUE 'FIRST_TIME',
normal TYPE string VALUE 'NORMAL',
END OF c_customer_type.
*----------------------------------------------------------------------*
* CLASS lcl_price_calculator IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_price_calculator IMPLEMENTATION.
METHOD calculate_total_price.
IF lv_is_risky_sell = abap_true.
lv_base_price = 15 * iv_no_of_products.
lv_delivery_costs = 2 * iv_no_of_products.
ev_total_price = lv_base_price + lv_delivery_costs.
ENDIF.
ENDMETHOD. "calculate_total_price
ENDCLASS.
Explanation: If you are accessing the attributes of a class inside and outside of the class directly and it
results in coupling between different code fragments, you can encapsulate the attributes in setter and getter
methods
Motivation:
• Hides the details of accessing or initialization of attributes
• Decouples client from the server with respect to the usage of attributes
• Allows subclasses of the server class to override the initialization or reading strategy of attributes
Steps of Refactoring:
• Create Setter and Getter methods for the attributes of the class
• Find all references to the attributes of the class and replace them with setter or getter method calls
• Change the visibility of your attributes to protected / private according to your needs
• Compile your code and run your ABAP Units
REPORT zsb_refact_encapsulate_attr.
*----------------------------------------------------------------------*
* CLASS lcl_customer DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_customer DEFINITION.
PUBLIC SECTION.
METHODS : constructor
IMPORTING iv_id TYPE ty_cust_id
iv_type TYPE i
iv_name TYPE string OPTIONAL
iv_surname TYPE string OPTIONAL
iv_adress TYPE string.
*----------------------------------------------------------------------*
* CLASS lcl_customer IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_customer IMPLEMENTATION.
METHOD constructor.
mv_id = iv_id.
mv_type = iv_type.
mv_adress = iv_adress.
mv_name = iv_name.
mv_surname = iv_surname.
ENDMETHOD. "constructor
START-OF-SELECTION.
WRITE lo_customer->mv_name.
WRITE lo_customer->mv_surname.
lo_customer->mv_adress = 'Sesame Street, 11'.
*&
*&---------------------------------------------------------------------*
REPORT zsb_refact_encaps_attr.
*----------------------------------------------------------------------*
* CLASS lcl_customer DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_customer DEFINITION.
PUBLIC SECTION.
METHODS : constructor
IMPORTING iv_id TYPE ty_cust_id
iv_type TYPE i
iv_name TYPE string OPTIONAL
iv_surname TYPE string OPTIONAL
iv_adress TYPE string,
*----------------------------------------------------------------------*
* CLASS lcl_customer IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_customer IMPLEMENTATION.
METHOD constructor.
mv_id = iv_id.
set_type( iv_type ).
set_adress( iv_adress ).
set_name( iv_name ).
set_surname( iv_surname ).
ENDMETHOD. "constructor
METHOD set_type.
mv_type = iv_type.
ENDMETHOD. "set_type
METHOD set_name.
mv_name = iv_name.
ENDMETHOD. "set_name
METHOD set_surname.
mv_surname = iv_surname.
ENDMETHOD. "set_surname
METHOD set_adress.
mv_adress = iv_adress.
ENDMETHOD. "set_adress
METHOD get_type.
rv_type = mv_type.
ENDMETHOD. "get_type
METHOD get_name.
rv_name = mv_name.
ENDMETHOD. "get_name
METHOD get_surname.
rv_surname = mv_surname.
ENDMETHOD. "get_surname
METHOD get_adress.
rv_adress = mv_adress.
ENDMETHOD. "get_adress
ENDCLASS. "lcl_customer IMPLEMENTATION
START-OF-SELECTION.
lv_name = lo_customer->get_name( ).
WRITE lv_name.
lo_customer->set_adress( 'Sesame Street, 11' ).
REPORT zsb_replace_literals.
lv_customer_type = 'P'.
lv_number_of_units_sold = 20.
IF lv_customer_type EQ 'P'.
lv_unit_price = 10.
ELSEIF lv_customer_type EQ 'C'.
lv_unit_price = 9.
ELSEIF lv_customer_type EQ 'U'.
lv_unit_price = 6.
ENDIF.
IF lv_customer_type EQ 'P'.
WRITE :/ 'The total price for a person is ', lv_total_price.
ELSEIF lv_customer_type EQ 'C'.
WRITE :/ 'The total price for a company is', lv_total_price.
ELSEIF lv_customer_type EQ 'U'.
WRITE :/ 'The total price for a university is', lv_total_price.
ENDIF.
REPORT zsb_replace_literals.
lv_customer_type = c_customer_person.
lv_number_of_units_sold = 20.
IF lv_customer_type EQ c_customer_person.
lv_unit_price = 10.
ELSEIF lv_customer_type EQ c_customer_company.
lv_unit_price = 9.
ELSEIF lv_customer_type EQ c_customer_university.
lv_unit_price = 6.
ENDIF.
IF lv_customer_type EQ c_customer_person.
WRITE :/ 'The total price for a person is ', lv_total_price.
ELSEIF lv_customer_type EQ c_customer_company.
WRITE :/ 'The total price for a company is', lv_total_price.
ELSEIF lv_customer_type EQ c_customer_university.
WRITE :/ 'The total price for a university is', lv_total_price.
ENDIF.
In the example application, the types of vehicles will be first handled using a type code and then by using
subclasses.
REPORT zsb_replace_type_code.
*----------------------------------------------------------------------*
* CLASS lcl_vehicle DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_vehicle DEFINITION.
PUBLIC SECTION.
CONSTANTS : c_car TYPE i VALUE 1,
c_truck TYPE i VALUE 2,
c_bus TYPE i VALUE 3.
METHODS : constructor
IMPORTING iv_vehicle_type TYPE i,
get_vehicle_name
RETURNING value(rv_vehicle_name) TYPE string,
get_maximum_velocity
RETURNING value(rv_maximum_velocity) TYPE i.
PRIVATE SECTION.
DATA : mv_vehicle_type TYPE i.
ENDCLASS. "lcl_vehicle DEFINITION
*----------------------------------------------------------------------*
* CLASS lcl_vehicle IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_vehicle IMPLEMENTATION.
METHOD constructor.
mv_vehicle_type = iv_vehicle_type.
ENDMETHOD. "constructor
METHOD get_vehicle_name.
CASE mv_vehicle_type.
WHEN c_car.
rv_vehicle_name = 'Car'.
WHEN c_bus.
rv_vehicle_name = 'Bus'.
WHEN c_truck.
rv_vehicle_name = 'Truck'.
ENDCASE.
ENDMETHOD. "get_vehicle_name
METHOD get_maximum_velocity.
CASE mv_vehicle_type.
WHEN c_car.
rv_maximum_velocity = 200.
WHEN c_bus.
rv_maximum_velocity = 180.
WHEN c_truck.
rv_maximum_velocity = 120.
ENDCASE.
ENDMETHOD. "get_maximum_velocity
ENDCLASS. "lcl_vehicle DEFINITION
START-OF-SELECTION.
CREATE OBJECT go_vehicle_1
EXPORTING
iv_vehicle_type = lcl_vehicle=>c_car.
gv_vehicle_name = go_vehicle_1->get_vehicle_name( ).
WRITE / gv_vehicle_name.
gv_vehicle_name = go_vehicle_2->get_vehicle_name( ).
WRITE / gv_vehicle_name.
Code After Code Refactoring
*&---------------------------------------------------------------------*
*& Report ZSB_REPLACE_TYPE_CODE_AFTER
*&
*&---------------------------------------------------------------------*
*&
*&
*&---------------------------------------------------------------------*
REPORT zsb_replace_type_code_after.
*----------------------------------------------------------------------*
* CLASS lcl_vehicle DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_vehicle DEFINITION ABSTRACT.
PUBLIC SECTION.
METHODS :
get_vehicle_name ABSTRACT
RETURNING value(rv_vehicle_name) TYPE string,
get_maximum_velocity ABSTRACT
RETURNING value(rv_maximum_velocity) TYPE i,
get_type ABSTRACT
RETURNING value(rv_vehicle_type) TYPE i.
CLASS-METHODS : create_vehicle
IMPORTING iv_vehicle_type TYPE i
RETURNING value(rv_vehicle) TYPE REF TO lcl_vehicle.
PRIVATE SECTION.
DATA : mv_vehicle_type TYPE i.
ENDCLASS. "lcl_vehicle DEFINITION
*----------------------------------------------------------------------*
* CLASS lcl_car DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_car DEFINITION INHERITING FROM lcl_vehicle.
PUBLIC SECTION.
METHODS : get_maximum_velocity REDEFINITION,
get_type REDEFINITION,
get_vehicle_name REDEFINITION.
*----------------------------------------------------------------------*
* CLASS lcl_truck DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_truck DEFINITION INHERITING FROM lcl_vehicle.
PUBLIC SECTION.
METHODS : get_maximum_velocity REDEFINITION,
get_type REDEFINITION,
get_vehicle_name REDEFINITION.
*----------------------------------------------------------------------*
* CLASS lcl_bus DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_bus DEFINITION INHERITING FROM lcl_vehicle.
PUBLIC SECTION.
METHODS : get_maximum_velocity REDEFINITION,
get_type REDEFINITION,
get_vehicle_name REDEFINITION.
*----------------------------------------------------------------------*
* CLASS lcl_vehicle IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_vehicle IMPLEMENTATION.
METHOD create_vehicle.
CASE iv_vehicle_type.
WHEN c_car.
CREATE OBJECT rv_vehicle TYPE lcl_car.
WHEN c_bus.
CREATE OBJECT rv_vehicle TYPE lcl_bus.
WHEN c_truck.
CREATE OBJECT rv_vehicle TYPE lcl_truck.
ENDCASE.
ENDMETHOD. "constructor
*----------------------------------------------------------------------*
* CLASS lcl_car DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_car IMPLEMENTATION.
METHOD get_vehicle_name.
rv_vehicle_name = 'Car'.
ENDMETHOD. "get_vehicle_name
METHOD get_maximum_velocity.
rv_maximum_velocity = 200.
ENDMETHOD. "get_maximum_velocity
METHOD get_type.
rv_vehicle_type = c_car.
ENDMETHOD. "get_type
ENDCLASS. "lcl_car DEFINITION
*----------------------------------------------------------------------*
* CLASS lcl_bus DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_bus IMPLEMENTATION.
METHOD get_vehicle_name.
rv_vehicle_name = 'Bus'.
ENDMETHOD. "get_vehicle_name
METHOD get_maximum_velocity.
rv_maximum_velocity = 180.
ENDMETHOD. "get_maximum_velocity
METHOD get_type.
rv_vehicle_type = c_bus.
ENDMETHOD. "get_type
ENDCLASS. "lcl_bus DEFINITION
*----------------------------------------------------------------------*
* CLASS lcl_truck DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_truck IMPLEMENTATION.
METHOD get_vehicle_name.
rv_vehicle_name = 'Truck'.
ENDMETHOD. "get_vehicle_name
METHOD get_maximum_velocity.
rv_maximum_velocity = 120.
ENDMETHOD. "get_maximum_velocity
METHOD get_type.
rv_vehicle_type = c_truck.
ENDMETHOD. "get_type
ENDCLASS. "lcl_truck DEFINITION
START-OF-SELECTION.
lcl_vehicle=>create_vehicle(
EXPORTING
iv_vehicle_type = lcl_vehicle=>c_car
RECEIVING
rv_vehicle = go_vehicle_1 ).
lcl_vehicle=>create_vehicle(
EXPORTING
iv_vehicle_type = lcl_vehicle=>c_truck
RECEIVING
rv_vehicle = go_vehicle_2 ).
gv_vehicle_name = go_vehicle_1->get_vehicle_name( ).
WRITE / gv_vehicle_name.
gv_vehicle_name = go_vehicle_2->get_vehicle_name( ).
WRITE / gv_vehicle_name.
Explanation of Refactoring Done in Code:
In the first report, there is only once class representing all kinds of vehicles and in the code of this class the
different behaviour for each kind of vehicle is separated using case-endcase or if –else..if statements. In the
second report, a factory method is added to the top level abstract vehicle class which instantiates instances
of different vehicle types, in the refactored code each vehicle type is represented by a subclass of the
vehicle class.
REPORT zsb_introduce_null_object.
*----------------------------------------------------------------------*
* CLASS lcl_person DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_person DEFINITION DEFERRED.
*----------------------------------------------------------------------*
* CLASS lcl_flat DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_flat DEFINITION.
PUBLIC SECTION.
METHODS : constructor
IMPORTING io_inhabitant TYPE REF TO lcl_person
iv_city TYPE string
iv_country TYPE string,
get_inhabitant
RETURNING value(ro_inhabitant) TYPE REF TO lcl_person.
PRIVATE SECTION.
*----------------------------------------------------------------------*
* CLASS lcl_person DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_person DEFINITION.
PUBLIC SECTION.
METHODS : get_name
RETURNING value(rv_name) TYPE string,
get_surname
RETURNING value(rv_surname) TYPE string,
get_age
RETURNING value(rv_age) TYPE i,
constructor
IMPORTING
iv_name TYPE string
iv_surname TYPE string
iv_age TYPE i.
PRIVATE SECTION.
DATA : mv_name TYPE string,
mv_surname TYPE string,
mv_age TYPE i.
*----------------------------------------------------------------------*
* CLASS lcl_person IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_person IMPLEMENTATION.
METHOD get_name.
rv_name = mv_name.
ENDMETHOD. "get_name
METHOD get_surname.
rv_surname = mv_surname.
ENDMETHOD. "get_surname
METHOD get_age.
rv_age = mv_age.
ENDMETHOD. "get_age
METHOD constructor.
mv_age = iv_age.
mv_surname = iv_surname.
mv_name = iv_name.
ENDMETHOD. "constructor
*----------------------------------------------------------------------*
* CLASS lcl_flat IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_flat IMPLEMENTATION.
METHOD constructor.
mo_inhabitant = io_inhabitant.
mv_city = iv_city.
mv_country = iv_country.
ENDMETHOD. "constructor
METHOD get_inhabitant.
ro_inhabitant = mo_inhabitant.
ENDMETHOD. "get_inhabitant
START-OF-SELECTION.
lo_inhabitant_test = lo_flat->get_inhabitant( ).
REPORT zsb_introduce_null_object_refc.
*----------------------------------------------------------------------*
* CLASS lcl_person DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_person DEFINITION DEFERRED.
*----------------------------------------------------------------------*
* CLASS lcl_flat DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_flat DEFINITION.
PUBLIC SECTION.
METHODS : constructor
IMPORTING io_inhabitant TYPE REF TO lcl_person
iv_city TYPE string
iv_country TYPE string,
get_inhabitant
RETURNING value(ro_inhabitant) TYPE REF TO lcl_person.
PRIVATE SECTION.
DATA : mo_inhabitant TYPE REF TO lcl_person,
mv_city TYPE string,
mv_country TYPE string.
ENDCLASS. "lcl_flat DEFINITION
*----------------------------------------------------------------------*
* CLASS lcl_person DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_person DEFINITION.
PUBLIC SECTION.
METHODS : get_name
RETURNING value(rv_name) TYPE string,
get_surname
RETURNING value(rv_surname) TYPE string,
get_age
RETURNING value(rv_age) TYPE i,
constructor
IMPORTING
iv_name TYPE string
iv_surname TYPE string
iv_age TYPE i.
PRIVATE SECTION.
DATA : mv_name TYPE string,
mv_surname TYPE string,
mv_age TYPE i.
*----------------------------------------------------------------------*
* CLASS lcl_null_person DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_null_person DEFINITION INHERITING FROM lcl_person.
PUBLIC SECTION.
METHODS : get_name REDEFINITION,
get_surname
REDEFINITION,
get_age
REDEFINITION,
constructor.
*----------------------------------------------------------------------*
* CLASS lcl_person IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_person IMPLEMENTATION.
METHOD get_name.
rv_name = mv_name.
ENDMETHOD. "get_name
METHOD get_surname.
rv_surname = mv_surname.
ENDMETHOD. "get_surname
METHOD get_age.
rv_age = mv_age.
ENDMETHOD. "get_age
METHOD constructor.
mv_age = iv_age.
mv_surname = iv_surname.
mv_name = iv_name.
ENDMETHOD. "constructor
*----------------------------------------------------------------------*
* CLASS lcl_flat IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_flat IMPLEMENTATION.
METHOD constructor.
mo_inhabitant = io_inhabitant.
mv_city = iv_city.
mv_country = iv_country.
ENDMETHOD. "constructor
METHOD get_inhabitant.
ro_inhabitant = mo_inhabitant.
ENDMETHOD. "get_inhabitant
*----------------------------------------------------------------------*
* CLASS lcl_null_person DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_null_person IMPLEMENTATION.
METHOD get_name.
rv_name = 'No name'.
ENDMETHOD. "get_name
METHOD get_surname.
rv_surname = 'No Surname'.
ENDMETHOD. "get_surname
METHOD get_age.
rv_age = 0.
ENDMETHOD. "get_age
METHOD constructor.
super->constructor( EXPORTING iv_name = space
iv_surname = space
iv_age = space
).
ENDMETHOD. "constructor
ENDCLASS. "lcl_null_person DEFINITION
START-OF-SELECTION.
lo_inhabitant_test = lo_flat->get_inhabitant( ).
lv_name = lo_inhabitant_test->get_name( ).
WRITE / lv_name.
lv_surname = lo_inhabitant_test->get_surname( ).
WRITE / lv_surname.
lv_age = lo_inhabitant_test->get_age( ).
WRITE / lv_age.
*&---------------------------------------------------------------------*
*& Report ZSB_SEPARATE_QUERY_FROM_MODIF
*&
*&---------------------------------------------------------------------*
*&
*&
*&---------------------------------------------------------------------*
REPORT zsb_separate_query_from_modif.
*----------------------------------------------------------------------*
* CLASS lcl_customer DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_customer DEFINITION.
PUBLIC SECTION.
METHODS : add_order_and_get_debt
IMPORTING iv_order_amount TYPE i
RETURNING value(rv_debt) TYPE i.
PRIVATE SECTION.
DATA : mv_debt TYPE i VALUE '1000',
mv_open_order_amount TYPE i VALUE '100'.
*----------------------------------------------------------------------*
* CLASS lcl_customer IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_customer IMPLEMENTATION.
METHOD add_order_and_get_debt.
ADD iv_order_amount TO mv_open_order_amount.
ADD iv_order_amount TO mv_debt.
rv_debt = mv_debt.
ENDMETHOD. "add_order_and_get_debt
ENDCLASS. "lcl_flat DEFINITION
START-OF-SELECTION.
WRITE / lv_debt.
REPORT zsb_separate_query_modif_ref.
*----------------------------------------------------------------------*
* CLASS lcl_customer DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_customer DEFINITION.
PUBLIC SECTION.
METHODS : get_debt
RETURNING value(rv_debt) TYPE i,
add_order_amount
IMPORTING iv_order_amount TYPE i.
PRIVATE SECTION.
DATA : mv_debt TYPE i VALUE '1000',
mv_open_order_amount TYPE i VALUE '100'.
*----------------------------------------------------------------------*
* CLASS lcl_customer IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_customer IMPLEMENTATION.
METHOD get_debt.
rv_debt = mv_debt.
ENDMETHOD. "add_order_and_get_debt
METHOD add_order_amount.
ADD iv_order_amount TO mv_open_order_amount.
ADD iv_order_amount TO mv_debt.
ENDMETHOD. "add_order_amount
ENDCLASS. "lcl_flat DEFINITION
START-OF-SELECTION.
lv_debt = lo_customer->get_debt( ).
WRITE / lv_debt.
REPORT zsb_parameterize_method.
*----------------------------------------------------------------------*
* CLASS lcl_product DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_product DEFINITION.
PUBLIC SECTION.
METHODS : constructor
IMPORTING iv_name TYPE string
iv_price TYPE p,
get_price
RETURNING value(rv_price) TYPE ty_price,
increase_price_10_percent,
increase_price_20_percent.
PRIVATE SECTION.
DATA : mv_price TYPE ty_price,
mv_name TYPE string.
*----------------------------------------------------------------------*
* CLASS lcl_product IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_product IMPLEMENTATION.
METHOD constructor.
mv_price = iv_price.
mv_name = iv_name.
ENDMETHOD. "constructor
METHOD get_price.
rv_price = mv_price.
ENDMETHOD. "get_price
METHOD increase_price_10_percent.
mv_price = mv_price * '1.1'.
ENDMETHOD. "increase_price_10_percent
METHOD increase_price_20_percent.
mv_price = mv_price * '1.2'.
ENDMETHOD. "increase_price_20_percent
ENDCLASS. "lcl_product IMPLEMENTATION
START-OF-SELECTION.
lo_product_1->increase_price_10_percent( ).
lv_price = lo_product_1->get_price( ).
WRITE / lv_price.
lo_product_1->increase_price_20_percent( ).
lv_price = lo_product_1->get_price( ).
WRITE / lv_price.
REPORT zsb_parameterize_method_ref.
*&---------------------------------------------------------------------*
*& Report ZSB_PARAMETERIZE_METHOD
*&
*&---------------------------------------------------------------------*
*&
*&
*&---------------------------------------------------------------------*
*----------------------------------------------------------------------*
* CLASS lcl_product DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_product DEFINITION.
PUBLIC SECTION.
METHODS : constructor
IMPORTING iv_name TYPE string
iv_price TYPE p,
get_price
RETURNING value(rv_price) TYPE ty_price,
increase_price
IMPORTING iv_increase_rate TYPE ty_increase_rate.
PRIVATE SECTION.
DATA : mv_price TYPE ty_price,
mv_name TYPE string.
*----------------------------------------------------------------------*
* CLASS lcl_product IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_product IMPLEMENTATION.
METHOD constructor.
mv_price = iv_price.
mv_name = iv_name.
ENDMETHOD. "constructor
METHOD get_price.
rv_price = mv_price.
ENDMETHOD. "get_price
METHOD increase_price.
mv_price = mv_price * ( 1 + iv_increase_rate ).
ENDMETHOD. "increase_price_10_percent
START-OF-SELECTION.
lo_product_1->increase_price( '0.1' ).
lv_price = lo_product_1->get_price( ).
WRITE / lv_price.
lo_product_1->increase_price( '0.2' ).
lv_price = lo_product_1->get_price( ).
WRITE / lv_price.
Step 2: Start the Refactoring Assistant following the menu item Utilities->Refactoring Assistant
Step 3: Select the attribute MV_SPEED and drag and drop it to the class ZCL_VEHICLE in the Refactoring
Assistant. You will have the following screen showing you that the member variable MV_SPEED is moved to
the superclass ZCL_VEHICLE. You have to activate the class ZCL_VEHICLE.
Step 4: Check the syntax of the class ZCL_BUS in the transaction SE24 . You will have the syntax error
showing that the variable MV_SPEED is already defined since we moved it to the superclass of the class
ZCL_BUS.
Step 5: Delete the attribute MV_SPEED from the attributes list of class ZCL_BUS and activate the class.
Step 2: Start the Refactoring Assistant following the menu item Utilities->Refactoring Assistant
Step 3:: Select the method GET_NAME and drag and drop it to the class ZCL_VEHICLE in the Refactoring
Assistant. You will have the following screen showing you that the instance method GET_NAME is moved to
the superclass ZCL_VEHICLE. You have to activate the class ZCL_VEHICLE.
Step 4: Check the syntax of the class ZCL_BUS in the transaction SE24 . You will have the syntax error
showing that the method GET_NAME is already defined since we moved it to the superclass of the class
ZCL_BUS.
Step 5: Delete the method GET_NAME from the attributes list of class ZCL_BUS and activate the class.
Copyright
© Copyright 2009 SAP AG. All rights reserved.
No part of this publication may be reproduced or transmitted in any form or for any purpose without the express permission of SAP AG.
The information contained herein may be changed without prior notice.
Some software products marketed by SAP AG and its distributors contain proprietary software components of other software vendors.
Microsoft, Windows, Excel, Outlook, and PowerPoint are registered trademarks of Microsoft Corporation.
IBM, DB2, DB2 Universal Database, System i, System i5, System p, System p5, System x, System z, System z10, System z9, z10, z9,
iSeries, pSeries, xSeries, zSeries, eServer, z/VM, z/OS, i5/OS, S/390, OS/390, OS/400, AS/400, S/390 Parallel Enterprise Server,
PowerVM, Power Architecture, POWER6+, POWER6, POWER5+, POWER5, POWER, OpenPower, PowerPC, BatchPipes,
BladeCenter, System Storage, GPFS, HACMP, RETAIN, DB2 Connect, RACF, Redbooks, OS/2, Parallel Sysplex, MVS/ESA, AIX,
Intelligent Miner, WebSphere, Netfinity, Tivoli and Informix are trademarks or registered trademarks of IBM Corporation.
Linux is the registered trademark of Linus Torvalds in the U.S. and other countries.
Adobe, the Adobe logo, Acrobat, PostScript, and Reader are either trademarks or registered trademarks of Adobe Systems
Incorporated in the United States and/or other countries.
Oracle is a registered trademark of Oracle Corporation.
UNIX, X/Open, OSF/1, and Motif are registered trademarks of the Open Group.
Citrix, ICA, Program Neighborhood, MetaFrame, WinFrame, VideoFrame, and MultiWin are trademarks or registered trademarks of
Citrix Systems, Inc.
HTML, XML, XHTML and W3C are trademarks or registered trademarks of W3C®, World Wide Web Consortium, Massachusetts
Institute of Technology.
Java is a registered trademark of Sun Microsystems, Inc.
JavaScript is a registered trademark of Sun Microsystems, Inc., used under license for technology invented and implemented by
Netscape.
SAP, R/3, SAP NetWeaver, Duet, PartnerEdge, ByDesign, SAP Business ByDesign, and other SAP products and services mentioned
herein as well as their respective logos are trademarks or registered trademarks of SAP AG in Germany and other countries.
Business Objects and the Business Objects logo, BusinessObjects, Crystal Reports, Crystal Decisions, Web Intelligence, Xcelsius, and
other Business Objects products and services mentioned herein as well as their respective logos are trademarks or registered
trademarks of Business Objects S.A. in the United States and in other countries. Business Objects is an SAP company.
All other product and service names mentioned are the trademarks of their respective companies. Data contained in this document
serves informational purposes only. National product specifications may vary.
These materials are subject to change without notice. These materials are provided by SAP AG and its affiliated companies ("SAP
Group") for informational purposes only, without representation or warranty of any kind, and SAP Group shall not be liable for errors or
omissions with respect to the materials. The only warranties for SAP Group products and services are those that are set forth in the
express warranty statements accompanying such products and services, if any. Nothing herein should be construed as constituting an
additional warranty.