Utilize CREATE TYPE para definir a especificação de um tipo de objeto e CREATE TYPE BODY para implementar seus métodos. Os tipos de objeto permitem agrupar atributos e métodos relacionados em uma única unidade composta, que pode ser referenciada posteriormente em outras definições de tipo ou colunas de tabela.
Estrutura do tipo de objeto
Um tipo de objeto é composto por duas partes:
|
Parte |
Instrução |
Finalidade |
|
Especificação do tipo de objeto |
|
Define atributos e assinaturas de métodos |
|
Corpo do tipo de objeto |
|
Implementa os métodos |
O corpo do tipo de objeto é obrigatório apenas quando o tipo inclui métodos. Caso você defina somente atributos, o corpo não será necessário.
Tipos de método
Os tipos de objeto suportam três categorias de métodos:
|
Tipo de método |
Invocado por |
Acessa atributos do objeto |
|
Método de membro |
Uma instância do tipo de objeto |
Sim |
|
Método estático |
O nome do tipo de objeto |
Não |
|
Método construtor |
Chamada direta (o nome corresponde ao tipo de objeto) |
Sim (via |
Crie um tipo de objeto apenas com atributos
Tipos de objeto sem métodos exigem apenas a especificação.
CREATE OR REPLACE TYPE addr_object_type AS OBJECT (
street VARCHAR2(30),
city VARCHAR2(20),
state CHAR(2),
zip NUMBER(5)
);
O tipo addr_object_type agrupa quatro atributos de endereço para que sejam tratados como uma unidade única em outras definições de tipo ou colunas de tabela. Como este tipo não possui métodos, não é necessário criar um corpo de tipo de objeto.
Métodos de membro
Um método de membro é uma função ou procedimento definido dentro de um tipo de objeto que opera sobre uma instância específica desse objeto. Esses métodos podem acessar e modifique os atributos da instância em que operam.
Defina um método de membro
Declare a assinatura do método em CREATE TYPE e implemente-o em CREATE TYPE BODY.
Especificação do tipo de objeto:
CREATE OR REPLACE TYPE emp_obj_type AS OBJECT (
empno NUMBER(4),
ename VARCHAR2(20),
addr addr_object_type,
MEMBER PROCEDURE display_emp(SELF IN OUT emp_obj_type)
);
Corpo do tipo de objeto:
CREATE OR REPLACE TYPE BODY emp_obj_type AS
MEMBER PROCEDURE display_emp (SELF IN OUT emp_obj_type)
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;
Dentro do corpo de um método de membro, referencie os atributos diretamente pelo nome (empno, ename) ou prefixados com SELF. (SELF.empno, SELF.ename). Ambas as formas são equivalentes:
CREATE OR REPLACE TYPE BODY emp_obj_type AS
MEMBER PROCEDURE display_emp (SELF IN OUT emp_obj_type)
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;
Comportamento do parâmetro SELF
|
Comportamento |
Detalhe |
|
Parâmetro implícito |
Todo método de membro possui um parâmetro |
|
Primeiro parâmetro |
O |
|
Modo padrão (procedimentos) |
|
Métodos estáticos
Um método estático pertence a um tipo de objeto, mas não está vinculado a nenhuma instância específica. Invoque-o utilizando o nome do tipo de objeto:
emp_obj_type.get_count();
Métodos estáticos não podem acessar nem modificar atributos de instâncias de objetos.
Defina um método estático
CREATE OR REPLACE TYPE dept_obj_type AS OBJECT (
deptno NUMBER(2),
STATIC FUNCTION get_dname(p_deptno IN NUMBER) RETURN VARCHAR2,
MEMBER PROCEDURE display_dept
);
CREATE OR REPLACE TYPE BODY dept_obj_type 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_type.get_dname(SELF.deptno));
END;
END;
Restrições de métodos estáticos
Referências a
SELFnão são permitidas dentro de uma função estática, pois ela não possui acesso implícito a nenhuma instância de objeto.Em um procedimento de membro (como
display_dept), o atributoSELF.deptnofica acessível mesmo sem a declaração explícita deSELFna lista de parâmetros.Para chamar uma função estática de dentro de um procedimento de membro, qualifique-a com o nome do tipo de objeto:
dept_obj_type.get_dname(SELF.deptno).
Métodos construtores
Um método construtor cria uma instância de um tipo de objeto e seu nome sempre corresponde ao nome do tipo. É possível sobrecarregar métodos construtores, definindo múltiplos construtores com o mesmo nome, mas com tipos de parâmetros diferentes.
Construtor padrão
O compilador SPL gera automaticamente um construtor padrão para cada tipo de objeto. Sua lista de parâmetros corresponde aos atributos do tipo na ordem de declaração, inicializando cada atributo como NULL.
Para o seguinte tipo de objeto:
CREATE TYPE address AS OBJECT
(
street_address VARCHAR2(40),
postal_code VARCHAR2(10),
city VARCHAR2(40),
state VARCHAR2(2)
)
O compilador SPL gera esta assinatura de construtor padrão:
CONSTRUCTOR FUNCTION address
(
street_address VARCHAR2(40),
postal_code VARCHAR2(10),
city VARCHAR2(40),
state VARCHAR2(2)
)
Construtores personalizados
Defina um construtor personalizado quando precisar calcular valores de atributos a partir de entradas parciais ou aplicar regras de negócio no momento da criação do objeto. Cenários comuns incluem:
|
Caso de uso |
Exemplo |
|
Cálculo de atributos derivados |
Obter |
|
Aplicação de regras de negócio |
Impedir a criação de objetos em estado inválido — por exemplo, um objeto de pagamento com valor |
Declare o construtor em CREATE TYPE e implemente-o em CREATE TYPE BODY:
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;
Para criar uma instância usando o construtor personalizado:
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;
Para substituir o construtor padrão — por exemplo, para bloquear valores NULL em um tipo de pagamento — declare um construtor personalizado cuja assinatura corresponda exatamente à do construtor padrão.