阅读(1853) (0)

PL/SQL 面向对象

2021-08-30 14:38:31 更新

在本章中,我们将讨论面向对象的PL/SQL。 PL/SQL允许定义一个对象类型,这有助于在Oracle中设计面向对象的数据库。 对象类型允许创建复合类型。使用对象可实现具有特定数据结构的真实世界对象以及操作它的方法。对象具有属性和方法。对象的属性用于存储对象的状态; 并使用方法来建模其行为。

对象是使用CREATE [OR REPLACE] TYPE语句创建的。 以下是创建一个由几个属性组成的简单地址(address)对象的例子 -

CREATE OR REPLACE TYPE address AS OBJECT 
(
  house_no varchar2(10), 
  street varchar2(30), 
  city varchar2(20), 
  state varchar2(10), 
  pincode varchar2(10) 
); 
/
SQL

当上面的代码在SQL提示符下执行时,它会产生以下结果 -

类型已创建。

下面再创建另一个对象:customer,将属性和方法包装在一起,以具有面向对象的感觉 -

CREATE OR REPLACE TYPE customer AS OBJECT 
(
 code number(5), 
 name varchar2(30), 
 contact_no varchar2(12), 
 addr address, 
 member procedure display 
); 
/
SQL

当上面的代码在SQL提示符下执行时,它会产生以下结果 -

类型已创建。

实例化对象

定义对象类型为对象提供模板(或蓝图)。要使用这个对象,需要创建这个对象的实例。可以使用实例名称和访问运算符(.)来访问对象的属性和方法,如下所示 -

SET SERVEROUTPUT ON SIZE 9999;
DECLARE 
   residence address; 
BEGIN 
   residence := address('1502A', '人民大道', '海口', '海南','201901'); 
   dbms_output.put_line('House No: '|| residence.house_no); 
   dbms_output.put_line('Street: '|| residence.street); 
   dbms_output.put_line('City: '|| residence.city); 
   dbms_output.put_line('Province: '|| residence.state); 
   dbms_output.put_line('Pincode: '|| residence.pincode); 
END; 
/
SQL

执行上面示例代码,得到以下结果 -


成员方法

成员方法用于操作对象的属性。在声明对象类型的同时提供成员方法的声明。 对象体定义了成员方法的代码。对象正文是使用CREATE TYPE BODY语句创建的。

构造函数是返回一个新对象作为其值的函数。每个对象都有一个系统定义的构造方法。构造函数的名称与对象类型相同。 例如 -

residence := address('1502A', '人民大道', '海口', '海南','201901');
SQL

比较方法用于比较对象。 有两种方法来比较对象 -

映射方法

Map方法是一个函数,它的值取决于属性的值。 例如,对于客户对象,如果客户代码对于两个客户是相同的,则两个客户可以是相同的。 所以这两个对象之间的关系将取决于代码的值。

排序方法

排序方法实现了一些用于比较两个对象的内部逻辑。例如,对于一个矩形对象,如果矩形的两边都较大,则矩形比另一个矩形大。

使用Map方法

下面尝试使用以下矩形对象来了解上述概念 -

SET SERVEROUTPUT ON SIZE 999999;
CREATE OR REPLACE TYPE rectangle AS OBJECT 
(
  length number, 
  width number, 
  member function enlarge( inc number) return rectangle, 
  member procedure display, 
  map member function measure return number 
); 
/
SQL

当上面的代码在SQL提示符下执行时,它会产生以下结果 -

类型已创建。

接下来,创建类型主体 -

CREATE OR REPLACE TYPE BODY rectangle AS 
   MEMBER FUNCTION enlarge(inc number) return rectangle IS 
   BEGIN 
      return rectangle(self.length + inc, self.width + inc); 
   END enlarge;  
   MEMBER PROCEDURE display IS 
   BEGIN  
      dbms_output.put_line('Length: '|| length); 
      dbms_output.put_line('Width: '|| width); 
   END display;  
   MAP MEMBER FUNCTION measure return number IS 
   BEGIN 
      return (sqrt(length*length + width*width)); 
   END measure; 
END; 
/
SQL

执行上面示例代码,得到以下输出结果 -

类型主体已创建。
Shell

现在使用矩形对象及其成员函数 -

SET SERVEROUTPUT ON SIZE 99999;
DECLARE 
   r1 rectangle; 
   r2 rectangle; 
   r3 rectangle; 
   inc_factor number := 5; 
BEGIN 
   r1 := rectangle(3, 4); 
   r2 := rectangle(5, 7); 
   r3 := r1.enlarge(inc_factor); 
   r3.display;  
   IF (r1 > r2) THEN -- calling measure function 
      r1.display; 
   ELSE 
      r2.display; 
   END IF; 
END; 
/
SQL

执行上面示例代码,得到以下输出结果 -


使用排序方法

现在,使用排序方法可以达到同样的效果。下面来看看如使用排序方法重新创建矩形对象 -

CREATE OR REPLACE TYPE rectangle AS OBJECT 
(
  length number, 
  width number, 
  member procedure display, 
  order member function measure(r rectangle) return number 
); 
/
SQL

当上面的代码在SQL提示符下执行时,它会产生以下结果 -

类型已创建。

创建类型主体 -

CREATE OR REPLACE TYPE BODY rectangle AS 
   MEMBER PROCEDURE display IS 
   BEGIN 
      dbms_output.put_line('Length: '|| length); 
      dbms_output.put_line('Width: '|| width); 
   END display;  
   ORDER MEMBER FUNCTION measure(r rectangle) return number IS 
   BEGIN 
      IF(sqrt(self.length*self.length + self.width*self.width)> 
         sqrt(r.length*r.length + r.width*r.width)) then 
         return(1); 
      ELSE 
         return(-1); 
      END IF; 
   END measure; 
END; 
/
SQL

执行上面示例代码,得到以下结果 -

类型主体已创建。
Shell

使用矩形对象及其成员函数 -

SET SERVEROUTPUT ON SIZE 99999;
DECLARE 
   r1 rectangle; 
   r2 rectangle; 
BEGIN 
   r1 := rectangle(23, 44); 
   r2 := rectangle(15, 17); 
   r1.display; 
   r2.display; 
   IF (r1 > r2) THEN -- calling measure function 
      r1.display; 
   ELSE 
      r2.display; 
   END IF; 
END; 
/
SQL

执行上面示例代码,得到以下结果 -


PL/SQL对象的继承

PL/SQL允许从现有的基础对象创建对象。为了实现继承,基类对象应该声明为NOT FINAL。默认是FINAL。

以下程序演示了PL/SQL对象中的继承。首先创建另一个名为TableTop对象,它是从Rectangle对象继承的。因此,需要创建这个基础的Rectangle对象,参考以下代码 -

CREATE OR REPLACE TYPE  rectangle FORCE AS OBJECT 
(
  length number, 
  width number, 
  member function enlarge( inc number) return rectangle, 
  NOT FINAL member procedure display) NOT FINAL 
/
SQL

执行上面示例代码,得到以下结果 -

类型已创建。
Shell

创建基本类型的主体 -

CREATE OR REPLACE TYPE BODY rectangle AS 
   MEMBER FUNCTION enlarge(inc number) return rectangle IS 
   BEGIN 
      return rectangle(self.length + inc, self.width + inc); 
   END enlarge;  
   MEMBER PROCEDURE display IS 
   BEGIN 
      dbms_output.put_line('Length: '|| length); 
      dbms_output.put_line('Width: '|| width); 
   END display; 
END; 
/
SQL

执行上面示例代码,得到以下结果 -

类型主体已创建。
Shell

创建子对象tabletop -

CREATE OR REPLACE TYPE tabletop UNDER rectangle 
(   
   material varchar2(20), 
   OVERRIDING member procedure display 
) 
/
SQL

执行上面示例代码,得到以下结果 -

类型已创建。
Shell

为子对象tabletop创建类型主体 -

CREATE OR REPLACE TYPE BODY tabletop AS 
OVERRIDING MEMBER PROCEDURE display IS 
BEGIN 
   dbms_output.put_line('Length: '|| length); 
   dbms_output.put_line('Width: '|| width); 
   dbms_output.put_line('Material: '|| material); 
END display; 
/
SQL

执行上面示例代码,得到以下结果 -

类型主体已创建。
Shell

使用tabletop对象及其成员函数 -

DECLARE 
   t1 tabletop; 
   t2 tabletop; 
BEGIN 
   t1:= tabletop(20, 10, 'Wood'); 
   t2 := tabletop(50, 30, 'Steel'); 
   t1.display; 
   t2.display; 
END;
/
SQL

当执行上面示例代码时,得到以下结果 -

Length: 20 
Width: 10 
Material: Wood 
Length: 50 
Width: 30 
Material: Steel
Shell

PL/SQL中的抽象对象

NOT INSTANTIABLE子句用来声明一个抽象对象。不能直接使用抽象对象, 必须创建抽象对象的子类型或子类型才能使用它的功能。

例如,

CREATE OR REPLACE TYPE rectangle AS OBJECT 
(length number, 
 width number, 
 NOT INSTANTIABLE NOT FINAL MEMBER PROCEDURE display)  
 NOT INSTANTIABLE NOT FINAL 
/
SQL

当上面的代码在SQL提示符下执行时,它会产生以下结果 -

类型已创建。