PL/SQL 私有对象方法
Posted
技术标签:
【中文标题】PL/SQL 私有对象方法【英文标题】:PL/SQL private object method 【发布时间】:2009-10-16 20:23:45 【问题描述】:我对 Oracle 的 PL/SQL(使用 10g)有点陌生,我想知道是否有办法在对象类型中创建私有方法,就像其他语言(Java、 C++、C# 等...)。我知道可以在包中创建私有方法,但我似乎无法为对象类型找到一种方法。我不断收到编译器错误告诉我:
错误:PLS-00539:子程序“FOO”在对象类型主体中声明 并且必须在对象类型规范中定义。
【问题讨论】:
【参考方案1】:好的,这是一个我非常简单地测试过的潜在解决方案,到目前为止它似乎有效:
创建一个将标记为 NOT FINAL 和 NOT INSTANTIABLE 的父对象类型,然后将所有私有代码放入其中。私有方法不会是真正私有的,但是将它们置于非最终且不可实例化的类型中会阻止它们被调用。在可实例化子类型中,通过 SELF 引用超类型中的“私有”方法。 示例:
create or replace type PrivateFoo under SuperFoo
(
member procedure setUpCommonFoo
) NOT INSTANTIABLE NOT FINAL;
create or replace type body PrivateFoo is
-- Member procedures and functions
member procedure setUpCommonFoo is
begin
SELF.someAttrib:='Some Common Default Value';
end;
end;
create or replace type Foo under PrivateFoo
(
CONSTRUCTOR FUNCTION Foo RETURN SELF AS RESULT,
CONSTRUCTOR FUNCTION Foo(fkey FooKey) RETURN SELF AS RESULT -- assume fkey is defined in SuperFoo, and FooKey type is defined somewhere else ;)
)
create or replace type body Foo is
--no-arg Constructor For basic Foo set up.
CONSTRUCTOR FUNCTION PartyConvertor RETURN SELF AS RESULT AS
BEGIN
self.setUpCommonFoo;
RETURN;
END;
--alt constructor for other situations...
CONSTRUCTOR FUNCTION PartyConvertor(fkey FooKey) RETURN SELF AS RESULT AS
BEGIN
self.setUpCommonFoo;
SELF.rarelyUsedAttrib:='Special Value!'; --just assume that someAttrib and rarelyUsedAttrib actually exist ;)
self.fkey := fkey;
RETURN;
END;
--Other Members go here...
end;
现在我不得不承认,我不太喜欢这种模式。这似乎很尴尬和笨拙。我可能会尽可能地避免使用对象类型并坚持使用包(或非常简单的对象类型)。 package-as-fatory 只帮助我解决构造函数的私有公共代码问题,而不是其他类型的公共代码重构。
...除非有更好的方法来处理对象类型....有人吗?有人吗?
【讨论】:
【参考方案2】:如果您只需要使用一个子程序中的子程序(函数/过程),PL/SQL 确实允许您在声明块中将一个子程序嵌套在另一个子程序中。
它没有私有方法或函数那么理想,但在创建继承层次结构之前可能值得一试。
create or replace type body some_t
as
member function foo
return varchar2
as
function some_private_foo
return varchar2
as
begin
return 'Foo!';
end some_private_foo;
begin
return some_private_foo();
end foo;
end;
如果您使用的是 Oracle 12,那么您很幸运。您可以使用 ACCESSIBLE BY 子句创建一个只有您的类型才能对其进行编码的包。在下面的示例中,PL/SQL 编译器将只允许 FOO_T 中的代码引用 FOO_PRIVATE_PKG。
CREATE OR REPLACE package foo_private_pkg
accessible by ( foo_t )
as
function some_private_foo ( object_in in out nocopy foo_t )
return varchar2;
end;
【讨论】:
【参考方案3】:pl/sql 对象中不能有私有方法,可以有多态性和继承,但不能有封装。
当你想要封装(私有方法)时,你可以使用 pl/sql 包。
不可能同时使用这三个。
【讨论】:
好的,这会让事情变得困难。我有一个具有多个构造函数的对象类型,它们并不都采用相同的参数,但它们都有 4-5 行通用代码。我已经发现 PL/SQL 不允许构造函数链接,所以我想我可以将通用设置代码放入私有方法中。对于这类问题有什么好的 PL/SQL 解决方案? 我不知道。也许您可以创建一个带有返回对象的重载函数的包?我现在没有可用的 Oracle,所以我无法尝试。将其视为替代工厂。 其实……这又提出了一个好点:如果我在一个对象类型的几个方法中找到共同的代码,我该如何重构它?我不能将它分解为私有方法,有没有办法将它分解为一个公共方法,该方法不能被它所在的类之外的任何东西调用?还是我们只需要将其记录为“内部管理方法 - 放手!!”并希望没有人在原来的类之外称它?【参考方案4】:这个问题的答案有些困难,但我会尽可能地解释它。首先,这不完全是甲骨文的错; ANSI SQL 定义了一种称为抽象数据类型 (ADT) 的东西,可用于扩展 SQL。我认为 Oracle 很好地遵循了他们的规范。缺少封装的部分原因在于在 SQL 中引用和存储对象的困难。但是,我不会在这里详细介绍,因为我自己并不完全理解。
ADT 可用于为您的数据(无论是在代码中还是在表格中)赋予结构,但它们不能非常复杂。例如,您不能让对象 A 具有对象 B,而对象 B 又具有对象 A。这不能存储在 SQL 表中。您可以通过在 Oracle 中使用 REF 来解决这个问题(不确定其他供应商是如何解决这个问题的),但这成为另一个需要在代码中解决的问题。
我发现 ADT 适用于非常简单的结构和非常简单的成员方法。任何更复杂的东西都需要包。通常,我会编写一个包来实现给定对象类型的成员方法,因为您不能在对象内部调用私有方法。
这是一种痛苦......
【讨论】:
以上是关于PL/SQL 私有对象方法的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Package Body oracle pl/sql 中添加第二个私有函数?