Decorator Design Pattern in Oracle PL/SQL: Using Object Type with Constructor

As I did with the Template Method Design Pattern I also tried to implement the “Decorator” Design Pattern in Oracle’s PL/SQL language.

English Deutsch/German

The Book “Head First – Design Patterns” perfectly describes the Decorator pattern.
So I wrote some Object Type to implement the Decorator. I’d like to have a DRINK class (Espresso or Tea) with just one attribute called “description” and a method which returns the price.

There are some specific classes to make instances like an Espresso. Other classes are “adding” sugar or cream to my espresso.
I’d like to receive following result:

— start with a Espresso —
descr= Espresso
price= 1
descr= Espresso, sugar
price= 1,2
descr= Espresso, sugar, Cream
price= 1,95

— start with a Tea —
descr= Tea
price= 3
descr= Tea, sugar
price= 3,2
descr= Tea, sugar, Cream
price= 3,95

The manuals are telling me about an pl/sql object type constructor. As there I’m running Oracle9i I tried with an empty constructor (no parameters):

drop type sugar_o;
drop type cream_o;
drop type additions_decorator_o;
drop type espresso_o;
drop type tea_o;
drop type drink_o;

——————————————————

— drink_o [abstract]

——————————————————
create or replace type drink_o as object (
description varchar2(200)
, member function getDescription return varchar2
, member function price return number
, constructor function drink_o return self as result
) not final not instantiable
;

create or replace type body drink_o as

— Constructor

constructor function drink_o return self as result
is
begin
self.description := ‘–unbekannt–‘;
return;
— dont forget to RETURN !
— Otherwise:
— Error at line 34
— ORA-06503: PL/SQL: Function returned without value
— ORA-06512: at “drink_O”, line 6
— ORA-06512: at line 4
end;

— Setters / Getters

member function price return number
is
begin
–return self.price();
— recursive call of the member function price()
— es gibt ja kein price Attribut !!!

return 0;
end;

member function getDescription return varchar2
is
begin
return self.description;
— return ‘test’;
end;

end;

——————————————————

— espresso_o [instantiable] concrete drinking object

——————————————————
create or replace type espresso_o under drink_o (
OVERRIDING member function price return number
, constructor function espresso_o return self as result
) final instantiable
;

create or replace type body espresso_o as

— Constructor

constructor function espresso_o return self as result
is
begin
self.description := ‘Espresso’;
return;
— dont forget to RETURN !
— Otherwise:
— Error at line 34
— ORA-06503: PL/SQL: Function returned without value
— ORA-06512: at “ESPRESSO_O”, line 6
— ORA-06512: at line 4
end;


— specific price for Espresso! Costs $ 1.-

OVERRIDING member function price return number
is
begin
return 1;
end;

end;

——————————————————

— tea_o [instantiable] concrete drinking object

——————————————————
create or replace type tea_o under drink_o (
OVERRIDING member function price return number
, constructor function tea_o return self as result
) final instantiable
;

create or replace type body tea_o as

— Constructor

constructor function tea_o return self as result
is
begin
self.description := ‘Tea’;
return;
— dont forget to RETURN !
— Otherwise:
— Error at line 34
— ORA-06503: PL/SQL: Function returned without value
— ORA-06512: at “tea_O”, line 6
— ORA-06512: at line 4
end;


— specific price for Tea! Costs $ 3.- (expensive!)

OVERRIDING member function price return number
is
begin
return 3;
end;

end;

——————————————————

— additions_decorator_o [not instantiable]

——————————————————
create or replace type additions_decorator_o under drink_o (
OVERRIDING member function getDescription return varchar2
) not final not instantiable
;

create or replace type body additions_decorator_o as

— private methods (overriding the drink_o class!)

OVERRIDING member function getDescription return varchar2
is
begin
return ‘—dekoriert—‘;
end;

end;

——————————————————

— sugar_o [instantiable] concrete additions object

——————————————————
create or replace type sugar_o under additions_decorator_o (
drink drink_o
, OVERRIDING member function getDescription return varchar2
, OVERRIDING member function price return number
, constructor function sugar_o(pdrink drink_o) return self as result
) final instantiable
;

create or replace type body sugar_o as

— Constructor

constructor function sugar_o(pdrink drink_o) return self as result
is
begin
self.drink := pdrink;
return;
— dont forget to RETURN !
— Otherwise:
— Error at line 34
— ORA-06503: PL/SQL: Function returned without value
— ORA-06512: at “ESPRESSO_O”, line 6
— ORA-06512: at line 4
end;


— private methods

OVERRIDING member function getDescription return varchar2
is
begin
return drink.getDescription ||’, Sugar’;
end;


— specific price for sugar! Costs $ 0.20

OVERRIDING member function price return number
is
begin
return drink.price + 0.20;
end;

end;

——————————————————

— cream_o [instantiable] concrete additions object

——————————————————
create or replace type cream_o under additions_decorator_o (
drink drink_o
, OVERRIDING member function getDescription return varchar2
, OVERRIDING member function price return number
, constructor function cream_o(pdrink drink_o) return self as result
) final instantiable
;

create or replace type body cream_o as

— Constructor

constructor function cream_o(pdrink drink_o) return self as result
is
begin
self.drink := pdrink;
return;
— dont forget to RETURN !
— Otherwise:
— Error at line 34
— ORA-06503: PL/SQL: Function returned without value
— ORA-06512: at “ESPRESSO_O”, line 6
— ORA-06512: at line 4
end;


— private methods

OVERRIDING member function getDescription return varchar2
is
begin
return drink.getDescription ||’, Cream’;
end;


— specific price for cream! Costs $ 0.75

OVERRIDING member function price return number
is
begin
return drink.price + 0.75;
end;

end;

——————————————————

— Testcase on drink

——————————————————
declare
— declaring two kind of drinks
aCoffee drink_o;
aTea drink_o;
begin
dbms_output.put_line(chr(10) ||’– start with a Espresso –‘);

— lets create a warm Espresso
aCoffee := espresso_o;
dbms_output.put_line(‘descr= ‘ ||aCoffee.getDescription);
dbms_output.put_line(‘price= ‘ ||aCoffee.price);

— lets add sugar to our Espresso
aCoffee := sugar_o(aCoffee);
dbms_output.put_line(‘descr= ‘ ||aCoffee.getDescription);
dbms_output.put_line(‘price= ‘ ||aCoffee.price);

— also lets add some cream to our Espresso, too
aCoffee := cream_o(aCoffee);
dbms_output.put_line(‘descr= ‘ ||aCoffee.getDescription);
dbms_output.put_line(‘price= ‘ ||aCoffee.price);

dbms_output.put_line(chr(10) ||’– start with a Tea –‘);

— lets create a warm Tea on a swiss mountain lodge
aTea := tea_o;
dbms_output.put_line(‘descr= ‘ ||aTea.getDescription);
dbms_output.put_line(‘price= ‘ ||aTea.price);

— lets add sugar to our Tea
aTea := sugar_o(aTea);
dbms_output.put_line(‘descr= ‘ ||aTea.getDescription);
dbms_output.put_line(‘price= ‘ ||aTea.price);

— also lets add some cream to our Tea, too
aTea := cream_o(aTea);
dbms_output.put_line(‘descr= ‘ ||aTea.getDescription);
dbms_output.put_line(‘price= ‘ ||aTea.price);

end;
.

.
The result is:

— start with a Espresso —
descr= Espresso
price= 1
descr= Espresso, sugar
price= 1,2
descr= Espresso, sugar, Cream
price= 1,95

— start with a Tea —
descr= Tea
price= 3
descr= Tea, sugar
price= 3,2
descr= Tea, sugar, Cream
price= 3,95

2 thoughts on “Decorator Design Pattern in Oracle PL/SQL: Using Object Type with Constructor”

  1. Just because no one has commented yet – I keep coming back to your examples as explanations on the implementation of these patterns in pl/sql.

  2. Pingback: Design Patterns in PL/SQL (Oracle) « SERPland

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Scroll to Top