SERPland Blog

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

· 1412 words · 7 minutes to read

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


Update 2024

Der Decorator-Entwurfsmuster in Oracle PL/SQL unter Verwendung von Objekttypen mit Konstruktor ist ein nützliches Konzept, das auch im Jahr 2024 relevant ist. Das Ziel dieses Musters ist es, das Verhalten von Objekten dynamisch zu erweitern, ohne die Klassenstruktur zu ändern.

Im Jahr 2024 sind die Grundprinzipien des Decorator-Entwurfsmusters immer noch gültig. Die Idee, Objekte um zusätzliche Funktionalitäten zu erweitern, ist nach wie vor relevant und wird in vielen modernen Anwendungen eingesetzt.

Aktualisierung für das Jahr 2024:

In den letzten Jahren hat sich die PL/SQL-Entwicklungsumgebung weiterentwickelt, und neue Funktionen wurden hinzugefügt, um die Implementierung von Entwurfsmustern wie dem Decorator-Muster zu erleichtern. Die Verwendung von Objekttypen mit Konstruktoren ist nach wie vor eine gängige Praxis, aber es gibt jetzt auch weitere Möglichkeiten, um die Flexibilität und Effizienz bei der Implementierung von Entwurfsmustern in PL/SQL zu verbessern.

Einige der fortschrittlichen IDEs bieten jetzt integrierte Tools und Vorlagen für die Implementierung von Entwurfsmustern, einschließlich des Decorator-Musters. Dadurch können Entwickler schneller und effizienter arbeiten, da der Boilerplate-Code automatisch generiert wird.

Einfluss von Cloud-Technologien:

Mit dem Aufkommen von Cloud-Technologien und Microservices-Architekturen hat die Modularität und Erweiterbarkeit von Anwendungen an Bedeutung gewonnen. Das Decorator-Entwurfsmuster passt gut zu diesen Trends, da es die Möglichkeit bietet, Funktionalitäten zu erweitern und zu kombinieren, um den Anforderungen von sich schnell ändernden Anwendungen gerecht zu werden.

Verwendung von Frameworks:

In vielen modernen PL/SQL-Projekten werden auch Frameworks wie Oracle APEX eingesetzt, die die Implementierung von Entwurfsmustern vereinfachen können. Diese Frameworks bieten oft eingebaute Funktionen und Strukturen, die die Verwendung von Entwurfsmustern wie dem Decorator-Muster erleichtern.

Zusammenfassung:

Das Decorator-Entwurfsmuster in Oracle PL/SQL mit Objekttypen und Konstruktoren ist auch im Jahr 2024 ein relevantes Konzept. Durch die Weiterentwicklung der PL/SQL-Entwicklungsumgebung und den Einsatz fortschrittlicher Technologien wie Cloud und Microservices hat sich die Art und Weise, wie Entwurfsmuster implementiert werden, weiterentwickelt. Es ist wichtig, mit diesen Entwicklungen Schritt zu halten, um effiziente und wartbare Anwendungen zu erstellen.