The Specification Pattern: a Tool to write more maintainable Business-Logic?
Let’s have a Look at a pseudo-Code:
lo_spec_can_be_used_for_production = lo_spec_factory->is_in_warehouse( )->and( lo_spec_factory->can_be_produced_with_machine_a( )->or( lo_spec_factory->can_be_produced_with_machine_b( ) ). )->and( lo_spec_factory->requires_fork_lift_to_move( )->not( ) ). IF lo_can_be_used_for_production->is_satisfied_by( lo_warehouse_unit) = abap_true. " Okay, we can use that Unit for Production! ENDIF.
Every Specification chained is a Question, that contains itself probably a lot of (complex) Business-Logic. If you read the Code, you read english Text and know what the intent of the Code is. It is an Alternative to the use of Multiple (nested) IF Statements.
Code with many Conditions can become hard to understand, looking at the Example above you can Imagine that it contains a lot of Conditions hat we have to put together.
IF ( lo_warehouse_unit->current_area = 'WAREHOUSE_1 OR lo_warehouse_unit->current_area = 'WAREHOUSE_2' ......... ) AND ( ( lo_warehouse_unit->material->width > 120 OR lo_warehouse_unit->material_height > 500 OR lo_warehouse_unit->material->total_weight < 200' ........ ) OR ( lo_warehouse_unit->material->width <= 120 OR lo_warehouse_unit->material_height <= 500 OR lo_warehouse_type->material->type= 'YZS' ) ) AND ( lo_warehouse_unit->total_weight < 123 OR lo_warehouse_unit->type = zif_warehouse_unit_type=>special_pallet OR ...... )
To make the code cleaner you could also extract the conditions in private bool Methods:
IF me->is_in_warehouse( lo_warehouse_unit ) AND ( can_be_produced_with_machine_a( lo_warehouse_unit ) OR can_be_produced_with_machine_b (lo_warehouse_unit ) ) AND ( does_not_require_fork_list_to_move( lo_warehouse_unit )
The Code is much cleaner this way and you don’t have to read the Implementation Details for every condition.
This maybe fine for many Situations – but consider you have complex Business-Logic Conditions, that are used in multiple Places of you Application. It’s is not a good Idea to copy & paste the IF Statement(s) – because the day of Change-Request will come.
Let’s have a look an ABAP Implementation of the Specification Pattern. Because you cannot inherit from the ZCL_ABSTRACT_SPECIFICATION in it’s local Class Definition the AND, OR and NOT Classes are Gobal Classes.
To Implement an Specification Class you you just have to inherit from ZCL_ABSTRACT_SPECIFICATION and redefine the ZIF_SPECIFICATION~IS_SATISFIED_BY Method.
To Hide the Implementation (the actual Specification Class), you can create a Factory Class which Methods return an ZIF_SPECIFICATION Instance.
In which Situations can the Specification Pattern by useful?
As you’ve seen the Specification Pattern in ABAP comes with a bit of Overhead. Let’s have a look at the pro’s and con’s:
- Conditions in human-readable Words
- Reduces the Amount of IF Statements
- Encapsulates the Conditions in Classes (can be tested in Isolation / may use internally an BRF+ Function?)
- Where-used search (Factory Methods)
- Increases Class & Object Count
- Slower Performance in frequent called (e.g. LOOP) Code Segments
- If you want to use generalised Specification Classes you have to cast from the “object” reference-Type.
In Scenarios that have complex Logic, that is used in multiples Places the Specification Pattern may help you to write Code that is easier to reuse, read and maintain.
Example ABAP Implementation
You can view and download the Example Implementation at GitHub, containing Text-Files with the Code for the Interface and the Classes.
- What do you think about the Specification Pattern in general and about the Example Implementation?
- Have you already used this Pattern, maybe in a different Variation?
- Have you cases in Mind where you would use the Specification Pattern?