您可以使用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。