views:

503

answers:

2

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 done 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.
A: 

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.

tuinstoel
Ok, that's going to make things difficult. I have an object type with multiple constructors, they don't all take the same arguments, but they all have 4-5 lines of common code. I had already found that PL/SQL does not allow constructor chaining, so I thought I could put the common set-up code into a private method.What's a good PL/SQL solution to this sort of problem?
PrivateMethodMan
I don't know. Maybe you can create a package with overloaded functions that return an object? I don't have Oracle available now so I can't try. Consider it to be an alternative factory.
tuinstoel
Actually... This raises another good point: If I find common code in several methods in an object type, how do I refactor it? I can't factor it into a private method, is there a way to factor it into a public method that can't be called by anything outside the class it exists in? Or do we just have to document it as an "internal house-keeping method - hands off!!" and hope that no one calls it outside the original class?
PrivateMethodMan
+1  A: 

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?

PrivateMethodMan