【问题标题】:PL/SQL: Any trick to avoid cloning of objects?PL/SQL:有什么技巧可以避免对象克隆?
【发布时间】:2014-10-30 11:30:48
【问题描述】:

如果我们在 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;

但这又打印了两个不同的句子,所以内部对象也被克隆了。

我可以将对象封装到其他类型的变量中以避免克隆内部对象吗?或者更一般地说,是否有一些技巧可以避免对象的克隆,同时提供一种简单的方法来使用它?

【问题讨论】:

  • 不确定您是否可以在 PL/SQL 上下文中使用 ref 避免 PLS-00536,您在第一句话中就暗示了这一点。你为什么要将同一个对象分配给两个变量呢?我猜你可以有一个关联的对象数组,并让你的变量保存这些对象的索引,但这种重定向可能会很痛苦。
  • 为了方便oo编程,需要引用copy。例如,如果您通过将一些其他对象传递给构造函数来创建对象,“o_c1 := c1(o_c2, o_c3);”,那么 o_c2 和 o_c3 可以作为属性存储到 o_c1 中,它们应该是相同的对象您在 o_c1 中使用(和更改)的对象,而不是它们的克隆。强大的 oo 编程需要对象引用。

标签: oracle object plsql clone


【解决方案1】:

根据 Alex 的建议(使用关联数组),我创建了一个封装对象的包,因此我们可以以抽象的方式使用它们,就好像它们是引用一样:

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 都包含同一个对象的相同索引(~reference)。语法有点复杂,但在访问属性和方法时仍然与标准对象操作非常相似。

将一个对象分配给其他对象与标准对象分配完全相同:

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;

这将我们带入另一个问题:哈希内容是持久性的(因为它是在一个包中),因此在我们创建对象时,将有越来越多的对象添加到哈希中(即使对象是由相同的函数创建的) )。一个解决方案是在我们处理完对象后从哈希中删除该对象:

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;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-02-17
    • 1970-01-01
    • 2011-03-17
    • 2020-11-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-23
    • 2018-10-11
    相关资源
    最近更新 更多