Inheritance and Object Evolution in Oracle 9i

One of the fundamental features of most object-oriented languages is inheritance. It is of prime importance in Java, for example, in that everything (except primitives) ultimately is a subclass of, or inherits from, objects. Much of the criticism of the object-relational features in Oracle 8i has centered on the lack of support for inheritance. Inheritance, however, is only one way that a class can be reused. Composition, which is supported by Oracle 8i, is at least as important. Nonetheless, inheritance is often considered a hallmark of object-orientation, and it is the most significant new feature in Oracle 9i.

Object evolution, the ability to alter existing objects, is another important feature in Oracle 9i. As we will see, much of the need for object evolution which, from a user point of view, is nothing more than using the ALTER TYPE statement is due to the additional maintenance that object types require when we use inheritance.

Inheritance

One of the main goals of object-oriented programming is to increase the reuse of code. One way to do this with objects is by identifying the characteristics that they have in common attributes and methods and encapsulating those characteristics into a class, a superclass, that other classes, subclasses, can share. In Oracle 9i, these are called supertypes and subtypes.

The textbook example of a superclass and its subclasses is a hierarchy beginning with Person as the superclass and Employee and Student as its subclasses. To model this in Oracle, we can create a Person object type. The syntax is the same as we saw before, except that we need to add one new option: NOT FINAL. By default, an object type is FINAL, meaning that it cannot be subclassed:

 SQL> CREATE TYPE PERSON_TYPE AS OBJECT (   2    NAME    VARCHAR2(32),   3    DOB     DATE,   4    SEX     CHAR(1),   5    MEMBER FUNCTION GETAGE RETURN NUMBER   6  ) NOT FINAL   7  / Type created. 

To create an employee subtype, we use a CREATE TYPE statement with UNDER plus the name of the supertype:

 SQL> CREATE TYPE EMPLOYEE_TYPE UNDER PERSON_TYPE (   2    COMPANY    VARCHAR2(25),   3    DEPARTMENT VARCHAR2(25),   4    SALARY     NUMBER,   5    JOB_TITLE  VARCHAR2(25),   6    HIRE_DATE  DATE,   7    MEMBER FUNCTION GETSENIORITY RETURN NUMBER   8  )   9  / Type created. 

We can use the SQL*Plus DESC command to examine the structure of the employee type and see that EMPLOYEE has not only the attributes and methods we declared in the CREATE TYPE EMPLOYEE statement but those that it inherits from PERSON as well (Figure 6-2):

 SQL> DESC EMPLOYEE_TYPE  EMPLOYEE_TYPE extends SCOTT.PERSON_TYPE  Name                                Null?    Type  ----------------------------------- -------- -------- ----  NAME                                         VARCHAR2(32)  DOB                                          DATE  SEX                                          CHAR(1)  COMPANY                                      VARCHAR2(25)  DEPARTMENT                                   VARCHAR2(25)  SALARY                                       NUMBER  JOB_TITLE                                    VARCHAR2(25)  HIRE_DATE                                    DATE METHOD ------  MEMBER FUNCTION GETAGE RETURNS NUMBER METHOD ------  MEMBER FUNCTION GETSENIORITY RETURNS NUMBER 
Figure 6-2. Object inheritance.

graphics/06fig02.gif

NOT INSTANTIABLE: Abstract Types and Methods

Oracle 9i supports many of the features that we are familiar with from Java. For example, we can create an abstract type: a type that cannot be instantiated. To create an abstract type, we add the option NOT INSTANTIABLE to our type specification. To use this type, we must first create a subtype that inherits from it.

If a type is NOT INSTANTIABLE, any or all of its methods can also be declared NOT INSTANTIABLE. This is a way to force subtypes to implement methods: If a subtype does not implement a superclass's NOT INSTANTIABLE method, the subtype itself must be declared NOT INSTANTIABLE.

Let's consider building a graphics library. We could start by defining a supertype SHAPE. It will contain the characteristics and behaviors we wish all our shapes to have in common, such as color and area. It will be abstract, or not instantiable, because any real shape must also include attributes that determine its geometry, based on lines, curves, points or some combination. We can declare the supertype like this:

 SQL> CREATE TYPE SHAPE_TYPE AS OBJECT (   2    COLOR         VARCHAR2(12),   3    OUTLINE_STYLE VARCHAR2(12),   4    NOT INSTANTIABLE MEMBER FUNCTION GETAREA RETURN NUMBER   5  ) NOT INSTANTIABLE NOT FINAL   6  / Type created. 

We want to be able to get a shape's area, but because there is no general way to calculate that, we don't implement it here. Instead, to make it a requirement that subtypes provide a way to calculate their area, we declare a noninstantiable GETAREA function.

Let's create a subtype ELLIPSE_TYPE. Because we plan on instantiating this type, we need to include the GETAREA() member function, which we'll implement in the type body. Because a GETAREA function is already declared in the supertype (even though it is NOT INSTANTIABLE), we must use the OVERRIDING option here.

 SQL> CREATE TYPE ELLIPSE_TYPE UNDER SHAPE_TYPE (   2    MINOR_AXIS  NUMBER,   3    MAJOR_AXIS  NUMBER,   4    CENTER      POINT_TYPE,   5    OVERRIDING MEMBER FUNCTION GETAREA RETURN NUMBER   6  )   7  / 

We must also include the OVERRIDING keyword when we create the type body.

 SQL> CREATE TYPE BODY ELLIPSE_TYPE AS   2   3    OVERRIDING MEMBER FUNCTION GETAREA   4        RETURN NUMBER AS   5        BEGIN   6            RETURN MINOR_AXIS*MAJOR_AXIS*3.1415927;   7        END;   8   9  END;  10  / 

Now we can create a table that includes ELLIPSE_TYPE and insert some data. Notice that the ELLIPSE_TYPE constructor takes as its arguments the attributes for both the supertype and the subtype, in that order; there is no separate constructor for the supertype.

 SQL> CREATE TABLE ELLIPSES (   2    LABEL    VARCHAR2(12),   3    ELLIPSE  ELLIPSE_TYPE   4  ); Table created. SQL> INSERT INTO ELLIPSES   2    VALUES ('One',   3      ELLIPSE_TYPE('Red','Bold',10,20,   4        POINT_TYPE(5,5))); 1 row created. 

We can query this the same as any other table with an object type. A simple query returns nested objects.

 SQL> SELECT * FROM ELLIPSES; LABEL ------------ ELLIPSE(COLOR, OUTLINE_STYLE, MINOR_AXIS, MAJOR_AXIS, CENTER(X, Y)) -------------------------------------------------------------------- One ELLIPSE_TYPE('Red', 'Bold', 10, 20, POINT_TYPE(5, 5)) 

As before, if we want to un-nest the objects, we need to use an alias for the table and qualify each column with dot notation.

 SQL> SELECT LABEL,   2    E.ELLIPSE.COLOR AS COLOR,   3    E.ELLIPSE.MAJOR_AXIS AS A,   4    E.ELLIPSE.MINOR_AXIS AS B,   5    E.ELLIPSE.CENTER.X AS X,   6    E.ELLIPSE.CENTER.Y AS Y   7  FROM ELLIPSES E; LABEL    COLOR         A          B          X            Y -------- -------- ------------- ---------- ---- ----------- One      Red          20         10          5            5 

Overriding isn't limited to NOT INSTANTIATED methods; a subtype can override any supertype method unless the method is declared FINAL in the supertype.

Oracle also supports overloaded functions methods that have the same name but take different arguments. For example, the SHAPE object type may have two methods called STRETCH() for increasing the size of a shape, one that takes a single parameter that increases the overall shape of an object, and one that takes two parameters that will increase the X and Y dimensions independently. Overloaded methods can be defined in a single type (such as these two STRETCH() methods in the SHAPE type) or in a subtype. If we were to create a subtype of SHAPE for three-dimensional shape (say SHAPE3D), we might want to add yet another STRETCH() method that allows us to stretch a shape in the Z-dimension.

Object Evolution

The addition of support for inheritance in Oracle 9i introduced a lot of new options, so adding support for object evolution makes managing object types somewhat easier. For example, the default for a type is FINAL, which means that we cannot subclass it. If it turns out in the course of development that we should have allowed something to be subclassed that we hadn't considered before, it is fairly easy to change it. If we wanted to allow ELLIPSE_TYPE to be subclassed, we can do that with the statement

 SQL> ALTER TYPE ELLIPSE_TYPE NOT FINAL CASCADE; Type altered. 

In addition to NOT FINAL, we need to include CASCADE in this case because the ELLIPSE_TYPE has a dependent object: the ELLIPSES table.

When we use Oracle's object-relational features, we introduce a lot of dependencies between types and tables. To deal with that, the ALTER TYPE statement has a number of options, such as CASCADE, that specify what should be done about dependents and their data. Failing to get this right can leave objects in an invalid state, and they won't work until they are fixed. Object evolution should be approached carefully. The best thing to do is to get it right the first time. In a development environment, we usually have the luxury of being able to drop everything types, tables, and data and start over; this is the next best thing.



Java Oracle Database Development
Java Oracle Database Development
ISBN: 0130462187
EAN: 2147483647
Year: 2002
Pages: 71

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net