开发者

PL/SQL private object method

I'm a bit new to Oracle's PL/SQL (using 10g), I was wondering if there's a way to make a private method in an object type, as is often do开发者_如何学Gone for private helper methods in other languages (Java, C++, C#, etc...). I know it is possible to make private methods in packages, but I can't seem to find a way to do this for object types. I keep getting compiler errors telling me:

Error: PLS-00539: subprogram 'FOO' is declared in an object type body 
and must be defined in the object type specification.


Ok, here's a potential solution that I tested very briefly, and it seems to work so far:

Create a parent object type that will marked as NOT FINAL and NOT INSTANTIABLE and then put all the private code in there. The private methods won't be truly private, but putting them in a type that is not final and not instantiable prevents them from being called. In the instantiable subtype, reference the "private" methods in the supertype through SELF. Example:


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;

Now I have to admit, I don't really like this pattern. It seems awkward and kludgy. I'm probably going to just avoid Object Types as much as I can and stick to packages (or very simlpe object types). A package-as-fatory only helps me solve the private common code problem for constructors, not for other types of common code refactoring.

...unless there's a better way to work with Object Types.... anyone? anyone?


If you just need to use the subprogram (function/procedure) from one subprogram PL/SQL does allow you to nest a subprogram within another in the declaration block.

It's not as ideal as having private methods or functions but it might be worth a try before you go creating an inheritance hierarchy.

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;

If you're on Oracle 12 you're in luck. You can create a package that only your type can code against using the ACCESSIBLE BY clause. In the example below the PL/SQL compiler will only allow code from FOO_T to reference 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;


You can't have private methods in pl/sql objects, you can have polymorphism and inheritance but no encapsulation.

When you want encapsulation (private methods) you can use pl/sql packages.

All three at once isn't possible.


The answer to this is somewhat difficult, but I'll explain it as best as I can. First, it's not completely Oracle's fault; ANSI SQL defines a thing called Abstract Data Types (ADT's) which can be used to extend SQL. Oracle follows their specifications pretty well I think. Part of the lack of encapsulation comes with the difficulty of referencing and storing objects in SQL. I won't get into the details here however since I don't fully understand it myself.

ADT's are useful to give structure to your data, either in code or in tables, but they can't be very complex. For example, you cannot have Object A that has Object B which again has Object A. This cannot be stored in a SQL table. You can get around this by using REFs in Oracle (not sure how other vendors go about this) but that becomes another problem to solve in code.

I've found that ADT's are good for very simple structures and very simple member methods. Anything more elaborate requires packages. Often, I'll write a package that implements member methods for a given Object Type, since you can't call private methods inside an object.

It is a pain...

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜