Abstract Pattern provides an interface for creating families of related or dependent objects without specifying their concrete classes. Inherited subclasses of the abstract super class would know which of the objects are required.
Concept
Before jumping into the demo, lets see the concept. This will help us to better understand how Abstract Factory can be achieved.
UML
It looks little complicated, but its not. These are the Participants in this UML:
- AbstractFactory: An interface with operations that creates abstract products
- ConcreteFactory: Implementation of the AbstractFactory which creates actual products
- AbstractProduct: An interface for each type of product object
- ConcreteProduct: implementation of the AbstractProduct. This object would be created by respective concrete factory
- Client: Creates object of the ConcreteFactory by using AbstractFactory interface
Design Time Consideration:
- Define an abstract superclass for the products.
- Inherit Subclasses from this super class as concrete products.
- Define an abstract superclass with abstract methods to create specific products
- Inherit Subclasses from this class as Concrete factories which would instantiate product objects as desired.
Demo
Let’s see the demo now. After going through the concepts it would be easier to understand the demo application.
Demo UML
For demo purpose, we’ll use this UML.
We have defined two product families, ABS_DATA and ABS_PRINT. Form ABS_DATA, we inherited two concrete products: DATA_FROM_FILE and DATA_FROM_DB. We also inherited two concrete products from ABS_PRINT, PRINT_SIMPLE and PRINT_ALV.
We have defined abstract factory class as REPORT. This has two abstract methods: GET_DATA( ) & PRINT_DATA( ). These methods would be redefined in the concrete factory classes: ComplexReport
and SimpleReport
. Complex Report uses DATA_FROM_DB and PRINT_ALV objects, whereas Simple Report uses DATA_FROM_FILE and PRINT_SIMPLE.
Code Lines
Here is the code snippet which achieves the Abstract Factory Design pattern.
REPORT znp_dp_abs_factory.
*=== .....
CLASS abs_data DEFINITION ABSTRACT.
PUBLIC SECTION.
METHODS: read_data ABSTRACT.
ENDCLASS. "abs_data DEFINITION
*===
CLASS data_from_file DEFINITION INHERITING FROM abs_data.
PUBLIC SECTION.
METHODS: read_data REDEFINITION.
ENDCLASS. "data_from_file DEFINITION
*
CLASS data_from_file IMPLEMENTATION.
METHOD read_data.
WRITE: / 'Reading data from File'.
ENDMETHOD. "read_data
ENDCLASS. "Data_from_file IMPLEMENTATION
*===
CLASS data_from_db DEFINITION INHERITING FROM abs_data.
PUBLIC SECTION.
METHODS: read_data REDEFINITION.
ENDCLASS. "data_from_db DEFINITION
*
CLASS data_from_db IMPLEMENTATION.
METHOD read_data.
WRITE: / 'Reading data from DATABASE TABLE'.
ENDMETHOD. "read_data
ENDCLASS. "Data_from_db IMPLEMENTATION
*===....
CLASS abs_print DEFINITION ABSTRACT.
PUBLIC SECTION.
METHODS: write_data ABSTRACT.
ENDCLASS. "abs_print DEFINITION
*===
CLASS print_alv DEFINITION INHERITING FROM abs_print.
PUBLIC SECTION.
METHODS: write_data REDEFINITION.
ENDCLASS. "print_alv DEFINITION
*
CLASS print_alv IMPLEMENTATION.
METHOD write_data.
WRITE: / 'Writing data into ALV'.
ENDMETHOD. "write_data
ENDCLASS. "print_alv IMPLEMENTATION
*===
CLASS print_simple DEFINITION INHERITING FROM abs_print.
PUBLIC SECTION.
METHODS: write_data REDEFINITION.
ENDCLASS. "print_simple DEFINITION
*
CLASS print_simple IMPLEMENTATION.
METHOD write_data.
WRITE: / 'Writing data in classic - This is actually classic'.
ENDMETHOD. "write_data
ENDCLASS. "print_simple IMPLEMENTATION
*=== ....
CLASS report DEFINITION ABSTRACT.
PUBLIC SECTION.
METHODS: get_data ABSTRACT,
print_data ABSTRACT.
ENDCLASS. "absfactory DEFINITION
*===
CLASS simplereport DEFINITION INHERITING FROM report.
PUBLIC SECTION.
METHODS: get_data REDEFINITION.
METHODS: print_data REDEFINITION.
ENDCLASS. "simplereport DEFINITION
*
CLASS simplereport IMPLEMENTATION.
METHOD get_data.
DATA: lo_data TYPE REF TO data_from_file.
CREATE OBJECT lo_data.
lo_data->read_data( ).
ENDMETHOD. "get_Data
METHOD print_data.
DATA: lo_print TYPE REF TO print_simple.
CREATE OBJECT lo_print.
lo_print->write_data( ).
ENDMETHOD. "print_data
ENDCLASS. "simplereport IMPLEMENTATION
*===
CLASS complexreport DEFINITION INHERITING FROM report.
PUBLIC SECTION.
METHODS: get_data REDEFINITION.
METHODS: print_data REDEFINITION.
ENDCLASS. "complexreport DEFINITION
*
CLASS complexreport IMPLEMENTATION.
METHOD get_data.
DATA: lo_data TYPE REF TO data_from_db.
CREATE OBJECT lo_data.
lo_data->read_data( ).
ENDMETHOD. "get_data
METHOD print_data.
DATA: lo_print TYPE REF TO print_alv.
CREATE OBJECT lo_print.
lo_print->write_data( ).
ENDMETHOD. "print_data
ENDCLASS. "complexreport IMPLEMENTATION
*===
CLASS lcl_main_app DEFINITION.
PUBLIC SECTION.
CLASS-METHODS: run.
ENDCLASS. "lcl_main_app DEFINITION
*
CLASS lcl_main_app IMPLEMENTATION.
METHOD run.
DATA: lo_report TYPE REF TO report.
* Simple report (FILE + write)
CREATE OBJECT lo_report TYPE simplereport.
lo_report->get_data( ).
lo_report->print_data( ).
* report for DB in ALV
CREATE OBJECT lo_report TYPE complexreport.
lo_report->get_data( ).
lo_report->print_data( ).
ENDMETHOD. "run
ENDCLASS. "lcl_main_app IMPLEMENTATION
START-OF-SELECTION.
lcl_main_app=>run( ).
Output
Output generated by the code snippet.
It is nice explanation of Abstract Factory usage. In UML diagram the inheritance is not shown properly. As per UML diagram principles, super class should have triangle attached to it. But here subclass has triangle. Could you please change to reflect the correct inheritance.
Hello Yellappa,
Thanks for pointing the error in UML. I have corrected the UML and uploaded back here.
I request you to let me know, if you find any other error in UML in any other post.
Regards,
Naimesh Patel