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?
| Herausforderung | Design Pattern | Vorteil |
|---|---|---|
| Unterschiedliche Objekt-Erzeugung | Factory | Entkopplung von Implementierung |
| Wechselnde Algorithmen | Strategy | Austauschbare Geschaeftslogik |
| Gemeinsame Ablaufstruktur | Template Method | Wiederverwendbarer Rahmen |
| Komplexe Subsysteme | Facade | Vereinfachte 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 PreisberechnungINTERFACE 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 DeutschlandCLASS 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 SchweizCLASS 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 InterfaceINTERFACE zif_discount_strategy. METHODS apply_discount IMPORTING iv_price TYPE decfloat34 is_customer TYPE zcustomer RETURNING VALUE(rv_result) TYPE decfloat34.ENDINTERFACE.
" Keine Rabatt-StrategieCLASS 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-StrategieCLASS 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 StaffelungCLASS 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 MethodCLASS 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 GeneratorCLASS 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 GeneratorCLASS 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?
| Situation | Pattern | Beispiel |
|---|---|---|
| Objekterzeugung abhaengig von Parametern | Factory | Preisberechnung je Land |
| Algorithmus austauschbar | Strategy | Rabattstrategien |
| Gleicher Ablauf, unterschiedliche Details | Template Method | Dokumentengenerierung |
| Komplexes Subsystem vereinfachen | Facade | Order Processing |
Anti-Patterns vermeiden
1. God Class - zu viel Verantwortung
" SCHLECHT: Eine Klasse macht allesCLASS 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 aufteilenCLASS zcl_order_validator DEFINITION. " Nur ValidierungCLASS zcl_price_calculator DEFINITION. " Nur PreisberechnungCLASS zcl_inventory_service DEFINITION. " Nur BestandCLASS zcl_order_facade DEFINITION. " Orchestrierung2. Hard-coded Abhaengigkeiten
" SCHLECHT: Direkte InstanziierungMETHOD process. DATA(lo_service) = NEW zcl_payment_service( ). " Nicht testbar lo_service->process( ).ENDMETHOD.
" GUT: Dependency InjectionMETHOD 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 TypenMETHOD 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 PatternMETHOD get_discount. rv_discount = mo_discount_strategy->calculate( is_customer ).ENDMETHOD.Best Practices fuer RAP
- Interfaces fuer Flexibilitaet: Definiere Interfaces fuer alle austauschbaren Komponenten
- Kleine, fokussierte Klassen: Jede Klasse hat eine Verantwortung
- Dependency Injection: Abhaengigkeiten ueber Constructor oder Factory injizieren
- Testbarkeit: Patterns ermoeglichen das Einsetzen von Mock-Objekten
- Dokumentation: Pattern-Namen im Code erwaehnen (
" Strategy Pattern)
Kombination von Patterns
In der Praxis werden Patterns oft kombiniert:
" Factory + Strategy KombinationCLASS 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
- RAP Grundlagen - Basis fuer Business Object Entwicklung
- Clean ABAP - Code-Qualitaet und Naming Conventions
- EML Entity Manipulation Language - Datenoperationen in RAP
- RAP Actions und Functions - Geschaeftslogik exponieren
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.