2014-09-05 55 views
3

如果我們將一個對象變量賦值給pl/sql中的其他對象變量,則該對象將被克隆,因爲pl/sql不適用於引用。例如,下面的代碼將打印兩個不同的句子:PL/SQL:避免克隆對象的技巧?

create or replace type cla as object -- class (would be very complex) 
(
    name varchar2(50) 
); 

declare 
    o1 cla; 
    o2 cla; 
begin 
    o1 := cla('hi cloning world'); 
    o2 := o1; 
    o1.name = 'goodbye cloning world'; 

    dbms_output.put_line('o1.name: ' || o1.name); 
    dbms_output.put_line('o2.name: ' || o2.name); 
end; 

所以,我以爲我可以封裝對象到其他對象(外部對象),如果我給你的外部對象到其他外部對象,則內部對象不會被克隆:

create or replace type cla as object -- class (would be very complex) 
(
    name varchar2(10) 
); 

create or replace type eo_c as object -- class to encapsulate objects 
(
    o cla        -- encapsulation is easy 
); 

declare 
    eo eo_c; 
    eo2 eo_c; 
begin 
    eo := eo_c(cla('n1'));   -- eo is easy to create 
    dbms_output.put_line('eo.name: ' || eo.o.name); -- real object is easy to access 

    eo2 := eo;  -- eo_c object is cloned, cla object shouldn't be cloned 
    eo.o.name := 'n2';  -- if eo.o == eo2.o then we are changing both names 
    dbms_output.put_line('eo.name: ' || eo.o.name); 
    dbms_output.put_line('eo2 name: ' || eo2.o.name); 
end; 

但是,再次打印兩個不同的句子,所以內部對象也被克隆了。

我可以將對象封裝到其他類型的變量中以避免克隆內部對象嗎?或者更一般地說,是否有一些技巧可以避免克隆對象,同時允許使用它的簡單方法?

+2

不知道你能避免PLS-00536與'ref'在PL/SQL上下文中,您在第一句中暗示了這一點。爲什麼你想分配相同的對象到兩個變量?我想你可以有一個關聯的對象數組,並讓你的變量將索引保存到那些對象中,但是重定向可能會很痛苦。 – 2014-09-05 15:33:12

+0

爲了便於編程,需要參考副本。例如,如果通過將其他對象傳遞給構造函數「o_c1:= c1(o_c2,o_c3);」來創建對象,則o_c2和o_c3可以作爲屬性存儲到o_c1中,並且它們應該與您正在使用(和更改)o_c1的對象,而不是它們的克隆。強大的oo編程需要對象引用。 – freesoft 2014-09-08 06:51:32

回答

1

基於亞歷克斯建議(使用關聯數組),我創建了一個封裝對象的封裝,因此我們可以以一種抽象的方式使用它們,好像它們是引用:

create or replace type cla as object  -- complex class 
(
    name varchar2(10) 
); 


create or replace package eo as  -- package to encapsulate objects 
    type ao_t      -- type for hash (associative array) 
     is table of cla 
     index by varchar2(100); 
    o ao_t;       -- hash of objects 
end; 


declare 
    o1 varchar2(100); 
    o2 varchar2(100); 
begin 
    o1 := 'o1';       -- objects are hash indexes now 
    eo.o(o1) := new cla('hi');   -- store new object into the hash 
    o2 := o1;       -- assign object == assign index 
    eo.o(o1).name := 'bye';    -- change object attribute 

    dbms_output.put_line('eo.o(o1).name: ' || eo.o(o1).name); 
    dbms_output.put_line('eo.o(o2).name: ' || eo.o(o2).name); -- equal? 
end; 

現在「再見'如預期的那樣用對象引用書寫兩次。關鍵是o1和o2都包含相同的索引(〜引用)到同一個對象。語法稍微複雜一些,但在訪問屬性和方法時仍然非常類似於標準對象操作。

分配一個目的是其他是完全一樣的標準對象分配:

o2 := o1; 

同樣爲使用對象作爲函數參數:

afunc(o1); 

在內部,afunc()將只使用O1與訪問方法或屬性的相同特殊語法(以及不需要指定的特殊語法):

eo.o(o1).attrib := 5; 
eo.o(o1).method('nice'); 
o3 := o1; 

使用這個技巧的唯一要求是爲我們要封裝的每個類添加一個散列(類型和變量)到eo包。


更新

o1 := 'o1'; 

可能是一個問題,如果,例如,我們創建一個函數,對象,因爲該功能還必須是:基於變量名的索引值知道程序其餘部分使用的所有值,以避免重複值。一種解決方案是從散列尺寸取值:

o1 := eo.o.count; 

這需要我們成其他問題:散列含量persitent(因爲它是成一個包),所以越來越多的對象將被添加到該散列作爲我們創建對象(即使對象是由相同的函數創建的)。一個解決辦法是從哈希刪除對象,當我們這個對象:

eo.o(o1) = null; 

所以固定程序是:

create or replace type cla as object  -- complex class 
(
    name varchar2(10) 
); 


create or replace package eo as  -- package to encapsulate objects 
    type ao_t      -- type for hash (associative array) 
     is table of cla 
     index by varchar2(100); 
    o ao_t;       -- hash of objects 
end; 


declare 
    o1 varchar2(100); 
    o2 varchar2(100); 
begin 
    o1 := eo.o.count;     -- index based on hash size 
    eo.o(o1) := new cla('hi');   -- store new object into the hash 
    o2 := o1;       -- assign object == assign index 
    eo.o(o1).name := 'bye';    -- change object attribute 

    dbms_output.put_line('eo.o(o1).name: ' || eo.o(o1).name); 
    dbms_output.put_line('eo.o(o2).name: ' || eo.o(o2).name); -- equal? 

    eo.o(o1) = null;     -- remove object 
    eo.o(o2) = null;     -- remove object (redundant) 
end;