PL/SQL by Example / Inheritance and Polymorphism
A key concept of object-oriented programming (OOP) is inheritance, which allows grouping properties and behaviors into a hierarchy. This way, new objects can automatically acquire functionality (methods, variables, constants, etc.) from their ancestor.
By default, an object prohibits inheritance, so modification with the NOT FINAL
modifier is necessary.
CREATE OR REPLACE TYPE Employee_T AS OBJECT( FullName VARCHAR2(100) , MEMBER FUNCTION mf_Display RETURN VARCHAR2 ) NOT FINAL; /
CREATE OR REPLACE TYPE BODY Employee_T AS MEMBER FUNCTION mf_Display RETURN VARCHAR2 IS BEGIN RETURN FullName; END; END; /
Overriding
Another very common OOP concept is method overriding. This allows subtypes to change the behavior of inherited procedures and functions and adapt them to specific requirements.
The method definition remains the same as in the ancestor, only it is preceded by the keyword OVERRIDING
.
CREATE OR REPLACE TYPE Programmer_T UNDER Employee_T( Salary NUMBER , OVERRIDING MEMBER FUNCTION mf_Display RETURN VARCHAR2 ); /
CREATE OR REPLACE TYPE BODY Programmer_T AS OVERRIDING MEMBER FUNCTION mf_Display RETURN VARCHAR2 IS BEGIN RETURN FullName||', '||Salary; END; END; /
Using the overridden function mf_Display
is straightforward; in the first case, only the full name is printed, in the second, both the name and salary.
DECLARE l_Employee Employee_T; l_Programmer Programmer_T; BEGIN l_Employee:=Employee_T('Francis Sauce'); dbms_output.put_line(l_Employee.mf_Display); -- Francis Sauce l_Programmer:=Programmer_T('Peter Novak', 20000); dbms_output.put_line(l_Programmer.mf_Display); -- Peter Novak, 20000 END; /
Polymorphism
An interesting situation occurs when a descendant is assigned to a variable of the ancestor type, i.e., to Employee_T
. In this case, the name along with the salary is printed. This is because the object is actually an instance of the type Programmer_T
. The technique where objects of different types respond to calls in a specific way is called polymorphism.
DECLARE l_Employee Employee_T; BEGIN l_Employee:=Programmer_T('Peter Novak', 20000); dbms_output.put_line(l_Employee.mf_Display); -- Peter Novak, 20000 END; /
If, for some reason, it is necessary to enforce the implementation defined in the ancestor on a descendant that overrides it, explicit conversion is required.
DECLARE l_Programmer Programmer_T; BEGIN l_Programmer:=Programmer_T('Peter Novak', 20000); dbms_output.put_line((l_Programmer AS Employee_T).mf_Display); -- Peter Novak END; /