Design Patterns fuer RAP: Bewaehrte Architekturmuster

kategorie
RAP
Veröffentlicht
autor
Johannes

Design Patterns sind bewaehrte Loesungsschablonen fuer wiederkehrende Probleme in der Softwareentwicklung. Im Kontext von RAP (RESTful ABAP Programming) helfen sie, flexible, wartbare und erweiterbare Business Objects zu entwickeln.

Warum Design Patterns in RAP?

HerausforderungDesign PatternVorteil
Unterschiedliche Objekt-ErzeugungFactoryEntkopplung von Implementierung
Wechselnde AlgorithmenStrategyAustauschbare Geschaeftslogik
Gemeinsame AblaufstrukturTemplate MethodWiederverwendbarer Rahmen
Komplexe SubsystemeFacadeVereinfachte Schnittstelle

Factory Pattern

Das Factory Pattern kapselt die Objekterzeugung und ermoeglicht es, die konkrete Implementierung zur Laufzeit zu bestimmen. In RAP ist dies besonders nuetzlich fuer:

  • Unterschiedliche Berechnungslogiken je nach Geschaeftskontext
  • Mandanten- oder landesspezifische Implementierungen
  • Testbarkeit durch Austausch von Produktions- gegen Mock-Implementierungen

Szenario: Preisberechnung nach Region

" Interface fuer Preisberechnung
INTERFACE zif_price_calculator.
METHODS calculate_price
IMPORTING
iv_base_price TYPE decfloat34
iv_quantity TYPE i
RETURNING
VALUE(rv_result) TYPE decfloat34.
ENDINTERFACE.
" Implementierung fuer Deutschland
CLASS zcl_price_calc_de DEFINITION.
PUBLIC SECTION.
INTERFACES zif_price_calculator.
ENDCLASS.
CLASS zcl_price_calc_de IMPLEMENTATION.
METHOD zif_price_calculator~calculate_price.
" Deutsche MwSt: 19%
rv_result = iv_base_price * iv_quantity * '1.19'.
ENDMETHOD.
ENDCLASS.
" Implementierung fuer Schweiz
CLASS zcl_price_calc_ch DEFINITION.
PUBLIC SECTION.
INTERFACES zif_price_calculator.
ENDCLASS.
CLASS zcl_price_calc_ch IMPLEMENTATION.
METHOD zif_price_calculator~calculate_price.
" Schweizer MwSt: 8.1%
rv_result = iv_base_price * iv_quantity * '1.081'.
ENDMETHOD.
ENDCLASS.

Factory-Klasse

CLASS zcl_price_calculator_factory DEFINITION
PUBLIC FINAL CREATE PRIVATE.
PUBLIC SECTION.
CLASS-METHODS get_instance
IMPORTING
iv_country_code TYPE land1
RETURNING
VALUE(ro_calculator) TYPE REF TO zif_price_calculator.
PRIVATE SECTION.
CLASS-DATA gt_instances TYPE HASHED TABLE OF REF TO zif_price_calculator
WITH UNIQUE KEY table_line.
ENDCLASS.
CLASS zcl_price_calculator_factory IMPLEMENTATION.
METHOD get_instance.
CASE iv_country_code.
WHEN 'DE'.
ro_calculator = NEW zcl_price_calc_de( ).
WHEN 'CH'.
ro_calculator = NEW zcl_price_calc_ch( ).
WHEN 'AT'.
ro_calculator = NEW zcl_price_calc_at( ).
WHEN OTHERS.
ro_calculator = NEW zcl_price_calc_default( ).
ENDCASE.
ENDMETHOD.
ENDCLASS.

Verwendung in RAP Behavior Implementation

CLASS lhc_order DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
METHODS calculate_total FOR DETERMINE ON SAVE
IMPORTING keys FOR Order~calculateTotal.
ENDCLASS.
CLASS lhc_order IMPLEMENTATION.
METHOD calculate_total.
READ ENTITIES OF zi_order IN LOCAL MODE
ENTITY Order
FIELDS ( CountryCode BasePrice Quantity )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_orders).
LOOP AT lt_orders INTO DATA(ls_order).
" Factory liefert die richtige Implementierung
DATA(lo_calculator) = zcl_price_calculator_factory=>get_instance(
iv_country_code = ls_order-CountryCode ).
DATA(lv_total) = lo_calculator->calculate_price(
iv_base_price = ls_order-BasePrice
iv_quantity = ls_order-Quantity ).
MODIFY ENTITIES OF zi_order IN LOCAL MODE
ENTITY Order
UPDATE FIELDS ( TotalPrice )
WITH VALUE #( ( %tky = ls_order-%tky
TotalPrice = lv_total ) ).
ENDLOOP.
ENDMETHOD.
ENDCLASS.

Strategy Pattern

Das Strategy Pattern ermoeglicht den Austausch von Algorithmen zur Laufzeit. Anders als beim Factory Pattern, das die Erzeugung kapselt, kapselt Strategy das Verhalten.

Szenario: Unterschiedliche Rabattstrategien

" Strategy Interface
INTERFACE zif_discount_strategy.
METHODS apply_discount
IMPORTING
iv_price TYPE decfloat34
is_customer TYPE zcustomer
RETURNING
VALUE(rv_result) TYPE decfloat34.
ENDINTERFACE.
" Keine Rabatt-Strategie
CLASS zcl_no_discount DEFINITION.
PUBLIC SECTION.
INTERFACES zif_discount_strategy.
ENDCLASS.
CLASS zcl_no_discount IMPLEMENTATION.
METHOD zif_discount_strategy~apply_discount.
rv_result = iv_price.
ENDMETHOD.
ENDCLASS.
" Prozentuale Rabatt-Strategie
CLASS zcl_percentage_discount DEFINITION.
PUBLIC SECTION.
INTERFACES zif_discount_strategy.
METHODS constructor
IMPORTING iv_percentage TYPE decfloat34.
PRIVATE SECTION.
DATA mv_percentage TYPE decfloat34.
ENDCLASS.
CLASS zcl_percentage_discount IMPLEMENTATION.
METHOD constructor.
mv_percentage = iv_percentage.
ENDMETHOD.
METHOD zif_discount_strategy~apply_discount.
rv_result = iv_price * ( 1 - mv_percentage / 100 ).
ENDMETHOD.
ENDCLASS.
" VIP-Kundenrabatt mit Staffelung
CLASS zcl_vip_discount DEFINITION.
PUBLIC SECTION.
INTERFACES zif_discount_strategy.
ENDCLASS.
CLASS zcl_vip_discount IMPLEMENTATION.
METHOD zif_discount_strategy~apply_discount.
" Staffelrabatt basierend auf Kundenumsatz
CASE is_customer-customer_tier.
WHEN 'GOLD'.
rv_result = iv_price * '0.85'. " 15% Rabatt
WHEN 'SILVER'.
rv_result = iv_price * '0.90'. " 10% Rabatt
WHEN 'BRONZE'.
rv_result = iv_price * '0.95'. " 5% Rabatt
WHEN OTHERS.
rv_result = iv_price.
ENDCASE.
ENDMETHOD.
ENDCLASS.

Context-Klasse mit Strategy

CLASS zcl_order_processor DEFINITION
PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
METHODS constructor
IMPORTING
io_discount_strategy TYPE REF TO zif_discount_strategy.
METHODS set_discount_strategy
IMPORTING
io_discount_strategy TYPE REF TO zif_discount_strategy.
METHODS calculate_final_price
IMPORTING
iv_price TYPE decfloat34
is_customer TYPE zcustomer
RETURNING
VALUE(rv_result) TYPE decfloat34.
PRIVATE SECTION.
DATA mo_discount_strategy TYPE REF TO zif_discount_strategy.
ENDCLASS.
CLASS zcl_order_processor IMPLEMENTATION.
METHOD constructor.
mo_discount_strategy = io_discount_strategy.
ENDMETHOD.
METHOD set_discount_strategy.
mo_discount_strategy = io_discount_strategy.
ENDMETHOD.
METHOD calculate_final_price.
rv_result = mo_discount_strategy->apply_discount(
iv_price = iv_price
is_customer = is_customer ).
ENDMETHOD.
ENDCLASS.

Verwendung in RAP Action

CLASS lhc_salesorder DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
METHODS apply_campaign_discount FOR MODIFY
IMPORTING keys FOR ACTION SalesOrder~applyCampaignDiscount
RESULT result.
ENDCLASS.
CLASS lhc_salesorder IMPLEMENTATION.
METHOD apply_campaign_discount.
READ ENTITIES OF zi_salesorder IN LOCAL MODE
ENTITY SalesOrder
ALL FIELDS
WITH CORRESPONDING #( keys )
RESULT DATA(lt_orders).
LOOP AT lt_orders INTO DATA(ls_order).
" Strategy basierend auf aktiver Kampagne waehlen
DATA lo_strategy TYPE REF TO zif_discount_strategy.
IF ls_order-CampaignCode = 'SUMMER25'.
lo_strategy = NEW zcl_percentage_discount( 25 ).
ELSEIF ls_order-CustomerTier IS NOT INITIAL.
lo_strategy = NEW zcl_vip_discount( ).
ELSE.
lo_strategy = NEW zcl_no_discount( ).
ENDIF.
DATA(lo_processor) = NEW zcl_order_processor( lo_strategy ).
DATA(lv_final_price) = lo_processor->calculate_final_price(
iv_price = ls_order-GrossPrice
is_customer = CORRESPONDING #( ls_order ) ).
MODIFY ENTITIES OF zi_salesorder IN LOCAL MODE
ENTITY SalesOrder
UPDATE FIELDS ( FinalPrice )
WITH VALUE #( ( %tky = ls_order-%tky
FinalPrice = lv_final_price ) ).
ENDLOOP.
result = VALUE #( FOR order IN lt_orders
( %tky = order-%tky
%param = CORRESPONDING #( order ) ) ).
ENDMETHOD.
ENDCLASS.

Template Method Pattern

Das Template Method Pattern definiert das Grundgeruest eines Algorithmus in einer Basisklasse, waehrend Unterklassen bestimmte Schritte ueberschreiben. Der Ablauf bleibt gleich, die Details variieren.

Szenario: Dokumentengenerierung mit unterschiedlichen Formaten

" Abstrakte Basisklasse mit Template Method
CLASS zcl_document_generator DEFINITION
PUBLIC ABSTRACT CREATE PUBLIC.
PUBLIC SECTION.
" Template Method - definiert den Ablauf
METHODS generate_document FINAL
IMPORTING
is_order TYPE zorder
RETURNING
VALUE(rv_document) TYPE string.
PROTECTED SECTION.
" Hook-Methoden - von Unterklassen implementiert
METHODS get_header ABSTRACT
IMPORTING is_order TYPE zorder
RETURNING VALUE(rv_header) TYPE string.
METHODS get_line_items ABSTRACT
IMPORTING is_order TYPE zorder
RETURNING VALUE(rv_items) TYPE string.
METHODS get_footer ABSTRACT
IMPORTING is_order TYPE zorder
RETURNING VALUE(rv_footer) TYPE string.
METHODS format_output ABSTRACT
IMPORTING iv_content TYPE string
RETURNING VALUE(rv_formatted) TYPE string.
ENDCLASS.
CLASS zcl_document_generator IMPLEMENTATION.
METHOD generate_document.
" Algorithmus-Struktur ist fix
DATA(lv_header) = get_header( is_order ).
DATA(lv_items) = get_line_items( is_order ).
DATA(lv_footer) = get_footer( is_order ).
DATA(lv_content) = |{ lv_header }{ lv_items }{ lv_footer }|.
rv_document = format_output( lv_content ).
ENDMETHOD.
ENDCLASS.

Konkrete Implementierungen

" HTML-Dokument Generator
CLASS zcl_html_document_generator DEFINITION
INHERITING FROM zcl_document_generator
PUBLIC FINAL CREATE PUBLIC.
PROTECTED SECTION.
METHODS get_header REDEFINITION.
METHODS get_line_items REDEFINITION.
METHODS get_footer REDEFINITION.
METHODS format_output REDEFINITION.
ENDCLASS.
CLASS zcl_html_document_generator IMPLEMENTATION.
METHOD get_header.
rv_header = |<html><head><title>Bestellung { is_order-order_id }</title></head>| &&
|<body><h1>Bestellung { is_order-order_id }</h1>| &&
|<p>Kunde: { is_order-customer_name }</p>|.
ENDMETHOD.
METHOD get_line_items.
rv_items = |<table><tr><th>Position</th><th>Artikel</th><th>Menge</th></tr>|.
LOOP AT is_order-items INTO DATA(ls_item).
rv_items = |{ rv_items }<tr><td>{ ls_item-pos }</td>| &&
|<td>{ ls_item-description }</td>| &&
|<td>{ ls_item-quantity }</td></tr>|.
ENDLOOP.
rv_items = |{ rv_items }</table>|.
ENDMETHOD.
METHOD get_footer.
rv_footer = |<p>Gesamtsumme: { is_order-total_amount } EUR</p></body></html>|.
ENDMETHOD.
METHOD format_output.
rv_formatted = iv_content.
ENDMETHOD.
ENDCLASS.
" Plain-Text Generator
CLASS zcl_text_document_generator DEFINITION
INHERITING FROM zcl_document_generator
PUBLIC FINAL CREATE PUBLIC.
PROTECTED SECTION.
METHODS get_header REDEFINITION.
METHODS get_line_items REDEFINITION.
METHODS get_footer REDEFINITION.
METHODS format_output REDEFINITION.
ENDCLASS.
CLASS zcl_text_document_generator IMPLEMENTATION.
METHOD get_header.
rv_header = |========================================\n| &&
|BESTELLUNG { is_order-order_id }\n| &&
|Kunde: { is_order-customer_name }\n| &&
|========================================\n|.
ENDMETHOD.
METHOD get_line_items.
rv_items = |Positionen:\n|.
LOOP AT is_order-items INTO DATA(ls_item).
rv_items = |{ rv_items } { ls_item-pos }. { ls_item-description } - Menge: { ls_item-quantity }\n|.
ENDLOOP.
ENDMETHOD.
METHOD get_footer.
rv_footer = |----------------------------------------\n| &&
|GESAMT: { is_order-total_amount } EUR\n| &&
|========================================|.
ENDMETHOD.
METHOD format_output.
rv_formatted = iv_content.
ENDMETHOD.
ENDCLASS.

Verwendung in RAP fuer Export-Actions

CLASS lhc_order DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
METHODS export_document FOR MODIFY
IMPORTING keys FOR ACTION Order~exportDocument
RESULT result.
ENDCLASS.
CLASS lhc_order IMPLEMENTATION.
METHOD export_document.
READ ENTITIES OF zi_order IN LOCAL MODE
ENTITY Order
ALL FIELDS
WITH CORRESPONDING #( keys )
RESULT DATA(lt_orders).
LOOP AT lt_orders INTO DATA(ls_order).
DATA lo_generator TYPE REF TO zcl_document_generator.
" Generator basierend auf Parameter waehlen
CASE ls_order-%param-format.
WHEN 'HTML'.
lo_generator = NEW zcl_html_document_generator( ).
WHEN 'TEXT'.
lo_generator = NEW zcl_text_document_generator( ).
WHEN 'PDF'.
lo_generator = NEW zcl_pdf_document_generator( ).
ENDCASE.
DATA(ls_order_data) = CORRESPONDING zorder( ls_order ).
DATA(lv_document) = lo_generator->generate_document( ls_order_data ).
" Ergebnis setzen
APPEND VALUE #( %tky = ls_order-%tky
%param = VALUE #( content = lv_document
format = ls_order-%param-format ) )
TO result.
ENDLOOP.
ENDMETHOD.
ENDCLASS.

Facade Pattern

Das Facade Pattern bietet eine vereinfachte Schnittstelle zu einem komplexen Subsystem. Es reduziert Abhaengigkeiten und macht die Nutzung komplexer Funktionalitaeten einfacher.

Szenario: Order Processing Facade

CLASS zcl_order_facade DEFINITION
PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
METHODS constructor.
" Vereinfachte Schnittstelle - ein Aufruf fuer komplexen Prozess
METHODS process_complete_order
IMPORTING
is_order TYPE zorder_create
RETURNING
VALUE(rs_result) TYPE zorder_result
RAISING
cx_order_processing.
METHODS cancel_order
IMPORTING
iv_order_id TYPE zorder_id
RETURNING
VALUE(rv_success) TYPE abap_bool
RAISING
cx_order_processing.
PRIVATE SECTION.
DATA mo_validator TYPE REF TO zcl_order_validator.
DATA mo_inventory TYPE REF TO zcl_inventory_service.
DATA mo_payment TYPE REF TO zcl_payment_service.
DATA mo_notification TYPE REF TO zcl_notification_service.
DATA mo_logger TYPE REF TO zcl_order_logger.
ENDCLASS.
CLASS zcl_order_facade IMPLEMENTATION.
METHOD constructor.
" Interne Dienste initialisieren
mo_validator = NEW zcl_order_validator( ).
mo_inventory = NEW zcl_inventory_service( ).
mo_payment = NEW zcl_payment_service( ).
mo_notification = NEW zcl_notification_service( ).
mo_logger = NEW zcl_order_logger( ).
ENDMETHOD.
METHOD process_complete_order.
" Komplexer Prozess hinter einfacher Schnittstelle
mo_logger->log_start( is_order ).
" 1. Validierung
DATA(lv_valid) = mo_validator->validate_order( is_order ).
IF lv_valid = abap_false.
RAISE EXCEPTION TYPE cx_order_processing
MESSAGE e001(zorder) WITH is_order-order_id.
ENDIF.
" 2. Bestandspruefung und Reservierung
DATA(lv_available) = mo_inventory->check_availability( is_order-items ).
IF lv_available = abap_false.
RAISE EXCEPTION TYPE cx_order_processing
MESSAGE e002(zorder).
ENDIF.
mo_inventory->reserve_items( is_order-items ).
" 3. Zahlungsabwicklung
TRY.
DATA(ls_payment) = mo_payment->process_payment(
iv_amount = is_order-total_amount
is_payment_method = is_order-payment_method ).
CATCH cx_payment_failed INTO DATA(lx_payment).
" Reservierung rueckgaengig machen
mo_inventory->release_reservation( is_order-items ).
RAISE EXCEPTION TYPE cx_order_processing
MESSAGE e003(zorder)
PREVIOUS lx_payment.
ENDTRY.
" 4. Bestellung finalisieren
rs_result-order_id = zcl_number_range=>get_next( 'ZORDER' ).
rs_result-status = 'CONFIRMED'.
rs_result-payment_ref = ls_payment-reference.
rs_result-created_at = utclong_current( ).
" 5. Benachrichtigungen
mo_notification->send_confirmation(
iv_email = is_order-customer_email
is_order = rs_result ).
mo_logger->log_success( rs_result ).
ENDMETHOD.
METHOD cancel_order.
mo_logger->log_cancellation_start( iv_order_id ).
" Stornierungsprozess
mo_inventory->release_reservation( iv_order_id ).
mo_payment->refund( iv_order_id ).
mo_notification->send_cancellation( iv_order_id ).
rv_success = abap_true.
mo_logger->log_cancellation_success( iv_order_id ).
ENDMETHOD.
ENDCLASS.

Verwendung in RAP Action

CLASS lhc_order DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
METHODS create_and_process FOR MODIFY
IMPORTING keys FOR ACTION Order~createAndProcess
RESULT result.
METHODS cancel FOR MODIFY
IMPORTING keys FOR ACTION Order~cancel
RESULT result.
ENDCLASS.
CLASS lhc_order IMPLEMENTATION.
METHOD create_and_process.
DATA(lo_facade) = NEW zcl_order_facade( ).
LOOP AT keys INTO DATA(ls_key).
TRY.
" Ein Aufruf - kompletter Prozess
DATA(ls_result) = lo_facade->process_complete_order(
is_order = ls_key-%param ).
" Erfolg zurueckmelden
APPEND VALUE #( %cid = ls_key-%cid
%param = ls_result )
TO result.
CATCH cx_order_processing INTO DATA(lx_error).
" Fehler in Reported ausgeben
APPEND VALUE #( %cid = ls_key-%cid )
TO failed-order.
APPEND VALUE #( %cid = ls_key-%cid
%msg = lx_error )
TO reported-order.
ENDTRY.
ENDLOOP.
ENDMETHOD.
METHOD cancel.
DATA(lo_facade) = NEW zcl_order_facade( ).
LOOP AT keys INTO DATA(ls_key).
TRY.
DATA(lv_success) = lo_facade->cancel_order( ls_key-OrderId ).
IF lv_success = abap_true.
MODIFY ENTITIES OF zi_order IN LOCAL MODE
ENTITY Order
UPDATE FIELDS ( Status )
WITH VALUE #( ( %tky = ls_key-%tky
Status = 'CANCELLED' ) ).
APPEND VALUE #( %tky = ls_key-%tky
%param = VALUE #( success = abap_true ) )
TO result.
ENDIF.
CATCH cx_order_processing INTO DATA(lx_error).
APPEND VALUE #( %tky = ls_key-%tky )
TO failed-order.
APPEND VALUE #( %tky = ls_key-%tky
%msg = lx_error )
TO reported-order.
ENDTRY.
ENDLOOP.
ENDMETHOD.
ENDCLASS.

Wann welches Pattern?

SituationPatternBeispiel
Objekterzeugung abhaengig von ParameternFactoryPreisberechnung je Land
Algorithmus austauschbarStrategyRabattstrategien
Gleicher Ablauf, unterschiedliche DetailsTemplate MethodDokumentengenerierung
Komplexes Subsystem vereinfachenFacadeOrder Processing

Anti-Patterns vermeiden

1. God Class - zu viel Verantwortung

" SCHLECHT: Eine Klasse macht alles
CLASS zcl_order_manager DEFINITION.
PUBLIC SECTION.
METHODS validate_order.
METHODS calculate_price.
METHODS calculate_tax.
METHODS apply_discount.
METHODS reserve_inventory.
METHODS process_payment.
METHODS send_email.
METHODS generate_pdf.
METHODS update_statistics.
ENDCLASS.
" GUT: Verantwortlichkeiten aufteilen
CLASS zcl_order_validator DEFINITION. " Nur Validierung
CLASS zcl_price_calculator DEFINITION. " Nur Preisberechnung
CLASS zcl_inventory_service DEFINITION. " Nur Bestand
CLASS zcl_order_facade DEFINITION. " Orchestrierung

2. Hard-coded Abhaengigkeiten

" SCHLECHT: Direkte Instanziierung
METHOD process.
DATA(lo_service) = NEW zcl_payment_service( ). " Nicht testbar
lo_service->process( ).
ENDMETHOD.
" GUT: Dependency Injection
METHOD constructor
IMPORTING
io_payment_service TYPE REF TO zif_payment_service.
mo_payment_service = io_payment_service.
ENDMETHOD.

3. Switch-Statements statt Polymorphie

" SCHLECHT: Switch fuer Typen
METHOD get_discount.
CASE iv_customer_type.
WHEN 'VIP'.
rv_discount = 15.
WHEN 'REGULAR'.
rv_discount = 5.
WHEN 'NEW'.
rv_discount = 10.
ENDCASE.
ENDMETHOD.
" GUT: Strategy Pattern
METHOD get_discount.
rv_discount = mo_discount_strategy->calculate( is_customer ).
ENDMETHOD.

Best Practices fuer RAP

  1. Interfaces fuer Flexibilitaet: Definiere Interfaces fuer alle austauschbaren Komponenten
  2. Kleine, fokussierte Klassen: Jede Klasse hat eine Verantwortung
  3. Dependency Injection: Abhaengigkeiten ueber Constructor oder Factory injizieren
  4. Testbarkeit: Patterns ermoeglichen das Einsetzen von Mock-Objekten
  5. Dokumentation: Pattern-Namen im Code erwaehnen (" Strategy Pattern)

Kombination von Patterns

In der Praxis werden Patterns oft kombiniert:

" Factory + Strategy Kombination
CLASS zcl_discount_factory DEFINITION.
PUBLIC SECTION.
CLASS-METHODS create_strategy
IMPORTING iv_campaign TYPE string
RETURNING VALUE(ro_strategy) TYPE REF TO zif_discount_strategy.
ENDCLASS.
CLASS zcl_discount_factory IMPLEMENTATION.
METHOD create_strategy.
CASE iv_campaign.
WHEN 'SUMMER'.
ro_strategy = NEW zcl_percentage_discount( 25 ).
WHEN 'VIP'.
ro_strategy = NEW zcl_vip_discount( ).
WHEN OTHERS.
ro_strategy = NEW zcl_no_discount( ).
ENDCASE.
ENDMETHOD.
ENDCLASS.

Weiterführende Themen

Fazit

Design Patterns sind keine Selbstzweck, sondern Werkzeuge fuer besseren Code. In RAP helfen sie besonders bei:

  • Flexibilitaet: Austauschbare Implementierungen ohne Aenderung der Aufrufer
  • Testbarkeit: Mock-Objekte statt echter Services in Unit Tests
  • Wartbarkeit: Kleine, verstaendliche Klassen statt monolithischer Code
  • Erweiterbarkeit: Neue Varianten ohne Aenderung bestehenden Codes

Beginne mit dem einfachsten Pattern, das dein Problem loest. Nicht jede Situation erfordert komplexe Muster - manchmal ist eine einfache IF-Abfrage die bessere Loesung.