【问题标题】:PL/SQL private object methodPL/SQL 私有对象方法
【发布时间】:2009-10-16 20:23:45
【问题描述】:

我对 Oracle 的 PL/SQL(使用 10g)有点陌生,我想知道是否有办法在对象类型中创建私有方法,就像其他语言(Java、 C++、C# 等...)。我知道可以在包中创建私有方法,但我似乎无法为对象类型找到一种方法。我不断收到编译器错误告诉我:

错误:PLS-00539:子程序“FOO”在对象类型主体中声明
并且必须在对象类型规范中定义。

【问题讨论】:

    标签: sql oracle plsql oracle10g


    【解决方案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 适用于非常简单的结构和非常简单的成员方法。任何更复杂的东西都需要包。通常,我会编写一个包来实现给定对象类型的成员方法,因为您不能在对象内部调用私有方法。

        这是一种痛苦......

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-12-12
          • 2012-10-11
          • 2015-12-29
          • 2015-09-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多