您可以使用CREATE TYPE命令创建对象类型规格,并可以使用CREATE TYPE BODY命令创建对象类型主体。本节提供一些如何使用 CREATE TYPE和CREATE TYPE BODY命令的示例。

第一个示例创建addr_object_type对象类型,其中只包含属性,不包含方法:

CREATE OR REPLACE TYPE addr_object_type AS OBJECT (
    street          VARCHAR2(30),
    city            VARCHAR2(20),
    state           CHAR(2),
    zip             NUMBER(5)
);

由于此对象类型中不存在方法,因此不需要对象类型主体。此示例创建了一个复合类型,使您可以将相关对象视为单个属性。

成员方法

成员方法是在某一对象类型中定义的函数或存储过程,只能通过该类型的实例进行调用。成员方法可访问它们运行所在的对象实例的属性,并且可更改这些属性。

以下对象类型规格创建emp_obj_typ对象类型:

CREATE OR REPLACE TYPE emp_obj_typ AS OBJECT (
    empno           NUMBER(4),
    ename           VARCHAR2(20),
    addr            ADDR_OBJ_TYP,
    MEMBER PROCEDURE display_emp(SELF IN OUT emp_obj_typ)
);

对象类型emp_obj_typ包含一个名为display_emp的成员方法。display_emp使用SELF参数,后者传递调用该方法的对象实例。

SELF参数的数据类型是所定义的对象类型的数据类型。SELF始终引用调用方法的实例。SELF参数是成员存储过程或函数中的第一个参数,无论它是否在参数列表中明确声明。

以下代码片段为Emp_obj_typ定义对象类型主体:

CREATE OR REPLACE TYPE BODY emp_obj_typ AS
    MEMBER PROCEDURE display_emp (SELF IN OUT emp_obj_typ)
    IS
    BEGIN
        DBMS_OUTPUT.PUT_LINE('Employee No   : ' || empno);
        DBMS_OUTPUT.PUT_LINE('Name          : ' || ename);
        DBMS_OUTPUT.PUT_LINE('Street        : ' || addr.street);
        DBMS_OUTPUT.PUT_LINE('City/State/Zip: ' || addr.city || ', ' ||
            addr.state || ' ' || LPAD(addr.zip,5,'0'));
    END;
END;

您也可以在对象类型主体中使用SELF参数。为阐释如何在CREATE TYPE BODY命令中使用SELF参数,上述对象类型主体可按如下所示编写:

CREATE OR REPLACE TYPE BODY emp_obj_typ AS
    MEMBER PROCEDURE display_emp (SELF IN OUT emp_obj_typ)
    IS
    BEGIN
        DBMS_OUTPUT.PUT_LINE('Employee No   : ' || SELF.empno);
        DBMS_OUTPUT.PUT_LINE('Name          : ' || SELF.ename);
        DBMS_OUTPUT.PUT_LINE('Street        : ' || SELF.addr.street);
        DBMS_OUTPUT.PUT_LINE('City/State/Zip: ' || SELF.addr.city || ', ' ||
            SELF.addr.state || ' ' || LPAD(SELF.addr.zip,5,'0'));
    END;
END;

这两个版本的emp_obj_typ主体完全相同。

静态方法

与成员方法一样,静态方法也属于某一类型。但是静态方法不是由类型的实例进行调用,而是通过使用类型的名称进行调用。例如,要调用 emp_obj_type 类型中定义的名为 get_count 的静态函数,您将编写以下语句:

emp_obj_type.get_count();

静态方法无权访问对象实例的属性,也不能更改这些属性,并且通常不使用类型的实例。

以下对象类型规格包含静态函数 get_dname 和成员存储过程 display_dept:

CREATE OR REPLACE TYPE dept_obj_typ AS OBJECT (
    deptno          NUMBER(2),
    STATIC FUNCTION get_dname(p_deptno IN NUMBER) RETURN VARCHAR2,
    MEMBER PROCEDURE display_dept
);

dept_obj_typ 的对象类型主体定义一个名为 get_dname 的静态函数和一个名为 display_dept 的成员存储过程:

CREATE OR REPLACE TYPE BODY dept_obj_typ AS
    STATIC FUNCTION get_dname(p_deptno IN NUMBER) RETURN VARCHAR2
    IS
        v_dname     VARCHAR2(14);
    BEGIN
        CASE p_deptno
            WHEN 10 THEN v_dname := 'ACCOUNTING';
            WHEN 20 THEN v_dname := 'RESEARCH';
            WHEN 30 THEN v_dname := 'SALES';
            WHEN 40 THEN v_dname := 'OPERATIONS';
            ELSE v_dname := 'UNKNOWN';
        END CASE;
        RETURN v_dname;
    END;
    MEMBER PROCEDURE display_dept
    IS
    BEGIN
        DBMS_OUTPUT.PUT_LINE('Dept No    : ' || SELF.deptno);
        DBMS_OUTPUT.PUT_LINE('Dept Name  : ' ||
            dept_obj_typ.get_dname(SELF.deptno));
    END;
END;

在静态函数 get_dname 中,不能有对 SELF 的引用。由于静态函数的调用独立于任何对象实例,因此没有对任何对象属性的隐式访问权。

成员存储过程 display_dept 可以访问 SELF 参数中传递的对象实例的 deptno 属性。不必在 display_dept 参数列表中明确声明 SELF 参数。

display_dept 存储过程中的最后一个 DBMS_OUTPUT.PUT_LINE 语句包含对静态函数 get_dname(由其对象类型名称 dept_obj_typ 限定)的调用。

构造函数方法

构造函数方法是一个函数,该函数通过为对象的成员分配值,创建对象类型的实例。对象类型可以定义多个构造函数来完成不同的任务。构造函数方法是一个成员函数(通过 SELF 参数进行调用),其名称与类型的名称相匹配。

例如,如果定义名为 address 的类型,则每个构造函数也名为 address。通过创建一个或多个同名但参数类型不同的不同构造函数,可以重载构造函数。

SPL 编译器将为每个对象类型提供默认构造函数。默认构造函数是一个成员函数,其名称与类型的名称匹配,并且其参数列表与类型成员也匹配(按顺序)。例如,给出如下对象类型:

CREATE TYPE address AS OBJECT
(
  street_address VARCHAR2(40),
  postal_code    VARCHAR2(10),
  city           VARCHAR2(40),
  state          VARCHAR2(2)
)

SPL 编译器将提供具有以下特征的默认构造函数:

CONSTRUCTOR FUNCTION address
(
  street_address VARCHAR2(40),
  postal_code    VARCHAR2(10),
  city           VARCHAR2(40),
  state          VARCHAR2(2)
)

默认构造函数的主体只是将每个成员设置为 NULL。

要创建自定义构造函数,请在 CREATETYPE 中声明该构造函数(使用关键字 constructor),然后在 CREATE TYPE BODY 命令中定义该构造函数。例如,您可能希望为 address 类型创建一个自定义构造函数,它在给出 street_address 和 postal_code 时计算城市和州。

CREATE TYPE address AS OBJECT
(
  street_address VARCHAR2(40),
  postal_code    VARCHAR2(10),
  city           VARCHAR2(40),
  state          VARCHAR2(2),

  CONSTRUCTOR FUNCTION address
   (
     street_address VARCHAR2,
     postal_code VARCHAR2
    ) RETURN self AS RESULT
)
 CREATE TYPE BODY address AS
  CONSTRUCTOR FUNCTION address
   (
     street_address VARCHAR2,
     postal_code VARCHAR2
    ) RETURN self AS RESULT
  IS
    BEGIN
      self.street_address := street_address;
      self.postal_code := postal_code;
      self.city := postal_code_to_city(postal_code);
      self.state := postal_code_to_state(postal_code);
      RETURN;
    END;
END;

要创建对象类型的实例,将调用该类型的某一构造函数方法。例如:

DECLARE
  cust_addr address := address('100 Main Street', 02203');
BEGIN
  DBMS_OUTPUT.PUT_LINE(cust_addr.city);  -- displays Boston
  DBMS_OUTPUT.PUT_LINE(cust_addr.state); -- displays MA
END;

自定义构造函数通常用于在给定的信息不完整时计算成员值。上一示例在给出邮政编码时计算 city 和 state 的值。

自定义构造函数还用于强制执行限制对象状态的业务规则。例如,如果定义一个对象类型来代表 payment,您可以使用自定义构造函数确保不能创建 amount 为 NULL、负数或零的 payment 类型的对象。默认构造函数将 payment.amount 设置为 NULL,因此您必须创建一个自定义构造函数(其特征与默认构造函数相匹配)来禁止金额为 NULL。