PL SQL 用戶指南和參考第十章PLSQL對(duì)象類型_第1頁
PL SQL 用戶指南和參考第十章PLSQL對(duì)象類型_第2頁
PL SQL 用戶指南和參考第十章PLSQL對(duì)象類型_第3頁
PL SQL 用戶指南和參考第十章PLSQL對(duì)象類型_第4頁
PL SQL 用戶指南和參考第十章PLSQL對(duì)象類型_第5頁
已閱讀5頁,還剩31頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、第十章 PL/SQL對(duì)象類型一、抽象的角色抽象是對(duì)一個(gè)真實(shí)世界實(shí)體的高級(jí)描述或建模。它能排除掉無關(guān)的細(xì)節(jié)內(nèi)容,使我們的日常生活更有條理。例如,駕駛一輛汽車時(shí),我們是不需要知道它的發(fā)動(dòng)機(jī)是如何工作的。由變速排檔、方向盤、加速器和剎車組成的接口就能讓我們有效地使用它。而其中每一項(xiàng)的詳細(xì)信息對(duì)于日常駕駛來說并不重要。 抽象是編程的核心內(nèi)容。例如,我們?cè)陔[藏一個(gè)復(fù)雜的算法時(shí)只要編寫一個(gè)過程,然后為它傳遞參數(shù)就可以做到過程化抽象。如果需要改變具體的實(shí)現(xiàn),換一個(gè)過程體即可。有了抽象后,那些調(diào)用過程的程序就不需要再修改了。 我們?cè)谥付ㄗ兞康臄?shù)據(jù)類型時(shí),可以使用數(shù)據(jù)抽象。數(shù)據(jù)類型代表了對(duì)于想操作的數(shù)值的值集合

2、和操作符集合。比方說一個(gè)POSITIVE類型的變量,只能存放正整數(shù),也只能用于加減乘等運(yùn)算。使用這個(gè)變量時(shí),我們不必知道PL/SQL是如何存儲(chǔ)整數(shù)或是實(shí)現(xiàn)算術(shù)運(yùn)算的。 對(duì)象類型是大多數(shù)編程語言內(nèi)置類型的一個(gè)概括。PL/SQL提供了大量的標(biāo)量類型和復(fù)合類型,每種類型都與一組預(yù)定義操作符相關(guān)聯(lián)。標(biāo)量類型(如 CHAR)是沒有內(nèi)部組成成分的。但復(fù)合類型(如RECORD)是有內(nèi)部組成成分的,并且其中每一個(gè)局部都可以被獨(dú)立操作。同RECORD類型一樣,對(duì)象類型也是復(fù)合類型。但是,它的操作是用戶自定義的,而不是預(yù)定義的。 目前,我們還不能用PL/SQL定義對(duì)象類型。它們必須用CREATE語句創(chuàng)立并存放在O

3、racle數(shù)據(jù)庫中,這樣才能被許多程序所共享。使用對(duì)象類型的程序稱為客戶端程序,它可以聲明并操作對(duì)象,但并不要求知道對(duì)象類型是如何表現(xiàn)數(shù)據(jù)或?qū)崿F(xiàn)操作。這就能夠讓我們分別編寫程序和對(duì)象類型,即便是在改變了對(duì)象實(shí)現(xiàn)時(shí)也不會(huì)影響到程序。因此,對(duì)象類型既支持過程化和又支持?jǐn)?shù)據(jù)抽象。 二、什么是對(duì)象類型對(duì)象類型是一個(gè)用戶自定義復(fù)合類型,它封裝了數(shù)據(jù)結(jié)構(gòu)和操作這個(gè)數(shù)據(jù)結(jié)構(gòu)的函數(shù)和過程。數(shù)據(jù)結(jié)構(gòu)中的變量稱為屬性,函數(shù)和過程稱為方法。通常,我們認(rèn)為對(duì)象(如人、車、銀行賬戶)都是有著屬性和行為的。例如一個(gè)嬰兒有性別、年齡和體重這些屬性,行為有吃、喝、睡等。對(duì)象類型能夠讓我們把這些內(nèi)容抽象出來并在應(yīng)用程序中使用。

4、 使用CREATE TYPE語句創(chuàng)立對(duì)象類型的時(shí)候,我們實(shí)際上是創(chuàng)立了真實(shí)世界中某個(gè)對(duì)象的抽象模板。模板只指定了我們?cè)诔绦蛑心苡玫降膶傩院托袨?。比方一個(gè)雇員有很多屬性,但通常只有他的一局部信息是我們的應(yīng)用程序所需要的,見以下圖: 假設(shè)我們現(xiàn)在需要編寫一個(gè)為雇員分發(fā)獎(jiǎng)金的程序。因?yàn)椴⒉皇枪蛦T的所有屬性都能用于解決這個(gè)問題,所以,我們只需設(shè)計(jì)一個(gè)抽象的雇員,擁有與解決問題相關(guān)的屬性即可:姓名、ID號(hào)、部門、職稱、工資和級(jí)別。然后,設(shè)計(jì)一些具體的操作方法,例如更改雇員的級(jí)別。 下一步就是定義用于數(shù)據(jù)表現(xiàn)的變量(屬性)和用于執(zhí)行操作的子程序集(方法)。最后,我們把屬性和方法封裝到對(duì)象類型中去。 對(duì)象的

5、屬性是公有的(對(duì)客戶端程序可見)。但是,設(shè)計(jì)良好的程序是不應(yīng)該直接操作這些屬性的,我們應(yīng)該為這些操作編寫相應(yīng)的方法。這樣,雇員數(shù)據(jù)就能保存在一個(gè)適宜的狀態(tài)。 在運(yùn)行時(shí),我們可以建立抽象雇員的實(shí)例(通常稱為對(duì)象),然后為它的屬性賦值。我們可以按照我們的需求創(chuàng)立任意多個(gè)實(shí)例。每個(gè)對(duì)象都有姓名、編號(hào)、職別等,如以下圖所示: 三、為什么使用對(duì)象類型對(duì)象類型能把大的系統(tǒng)劃分為多個(gè)邏輯實(shí)體,簡化系統(tǒng)復(fù)雜度。這就使我們可以創(chuàng)立模塊化、可維護(hù)、可重用的組件。也能讓不同小組的程序員并行開發(fā)軟件組件。 對(duì)象類型靠封裝數(shù)據(jù)的操作來把數(shù)據(jù)維護(hù)代碼從SQL腳本中別離出來,并把PL/SQL塊封裝到方法里。使用對(duì)象方法可以

6、防止很多在數(shù)據(jù)訪問時(shí)帶來的負(fù)面影響,同時(shí),對(duì)象類型隱藏實(shí)現(xiàn)細(xì)節(jié),更新細(xì)節(jié)內(nèi)容時(shí)不必修改客戶端程序。 對(duì)象類型可以為現(xiàn)實(shí)數(shù)據(jù)建模?,F(xiàn)實(shí)世界中的復(fù)雜實(shí)體和關(guān)系都可以直接映射到對(duì)象類型中。并且,對(duì)象類型還可以直接映射到面向?qū)ο笳Z言(如Java和C+)的類中。 四、對(duì)象類型的結(jié)構(gòu)與包相同,對(duì)象類型也有兩局部:說明和體,如以下圖所示。說明局部是應(yīng)用程序接口;它聲明了數(shù)據(jù)結(jié)構(gòu)(屬性集合)和所需的操作(方法)。方法體局部是對(duì)已聲明方法的實(shí)現(xiàn)。 客戶端程序要使用到的所有方法都在說明中聲明。我們可以把對(duì)象說明想象成一個(gè)可選的接口,把對(duì)象體想象成一個(gè)黒盒。我們可以在不改變說明局部的前提下調(diào)試,增強(qiáng)或替換對(duì)象體,并

7、且不會(huì)對(duì)客戶端程序造成影響。 在一個(gè)對(duì)象說明中,所有的屬性都必須聲明在方法之前。只有子程序的聲明才需要實(shí)現(xiàn)。所以,如果一個(gè)對(duì)象類型的說明只聲明了屬性,那么對(duì)象類型的體就沒有必要了。我們不能在對(duì)象體中聲明屬性。對(duì)象說明中的聲明都是公有的。 為了能更好的了解結(jié)構(gòu),請(qǐng)看下面的例子。這是一個(gè)復(fù)數(shù)的對(duì)象類型,有實(shí)數(shù)局部和虛數(shù)局部,并有幾個(gè)與復(fù)數(shù)操作相關(guān)的方法。 CREATE TYPE complex AS OBJECT(  rpart   REAL,   - attribut

8、e  ipart   REAL,  MEMBER FUNCTION plus(x complex)    RETURN complex,   - method  MEMBER FUNCTION LESS(x complex)    RETURN complex,  MEMBER 

9、FUNCTION times(x complex)    RETURN complex,  MEMBER FUNCTION divby(x complex)    RETURN complex);CREATE TYPE BODY complex AS  MEMBER FUNCTION plus(x complex)  

10、  RETURN complex IS  BEGIN    RETURN complex(rpart + x.rpart, ipart + x.ipart);  END plus;  MEMBER FUNCTION LESS(x complex)    RETURN complex IS 

11、 BEGIN    RETURN complex(rpart - x.rpart, ipart - x.ipart);  END LESS;  MEMBER FUNCTION times(x complex)    RETURN complex IS  BEGIN    RETURN

12、60;complex(rpart * x.rpart - ipart * x.ipart,                   rpart * x.ipart + ipart * x.rpart);  END times;  MEMBER&

13、#160;FUNCTION divby(x complex)    RETURN complex IS    z   REAL := x.rpart * 2 + x.ipart * 2;  BEGIN    RETURN complex(rpart * x.rpart 

14、+ ipart * x.ipart) / z,                   (ipart * x.rpart - rpart * x.ipart) / z);  END divby;END; 五、對(duì)象類型組件對(duì)象類型封裝了數(shù)據(jù)和操作。我們可以

15、在對(duì)象類型說明中聲明屬性和方法,但不能聲明常量、異常、游標(biāo)或類型。我們至少要聲明一個(gè)屬性(最多1000個(gè)),方法是可選的。 1、屬性同變量一樣,屬性也有名稱和數(shù)據(jù)類型。對(duì)象類型中的名稱必須是唯一的(但在其他的對(duì)象類型中可以重用)。除了下面幾種類型之外,其他任何Oralce類型都可以使用: 1. LONG和LONG RAW 2. ROWID和UROWID 3. PL/SQL特定類型BINARY_INTEGER及它的子類型、BOOLEAN、PLS_INTEGER、RECORD、REF CURSOR、%TYPE和%ROWTYPE 4. PL/SQL包內(nèi)定義的數(shù)據(jù)類型 我們不能在聲明屬性的時(shí)候用賦值語

16、句或DEFAULT子句為它初始化。同樣,也不能對(duì)屬性應(yīng)用NOT NULL約束。但是,對(duì)象是可以存放到添加了約束的數(shù)據(jù)表中。 數(shù)據(jù)結(jié)構(gòu)中的屬性集合依賴于真實(shí)世界中的對(duì)象。例如,為了表現(xiàn)一個(gè)分?jǐn)?shù),我們只需要兩個(gè)INTEGER類型的變量。另一方面,要是表現(xiàn)一個(gè)學(xué)生,我們需要幾個(gè)VARCHAR2來存放姓名、住址、 號(hào)碼和狀態(tài)等,再添加一個(gè)VARRAY類型變量用來存儲(chǔ)課程和分?jǐn)?shù)。 數(shù)據(jù)結(jié)構(gòu)可能是復(fù)雜的。例如,一個(gè)屬性的數(shù)據(jù)類型可能是另外一個(gè)對(duì)象類型(稱為嵌套對(duì)象類型)。有些對(duì)象類型,像隊(duì)列、鏈表和樹,都是動(dòng)態(tài)的,它們是隨著使用的需要而動(dòng)態(tài)改變存儲(chǔ)長度的。遞歸對(duì)象類型能夠直接或間接的包含自身類型,這樣就能

17、創(chuàng)立出更詭異的數(shù)據(jù)類型。 2、方法一般的,方法就是用關(guān)鍵字MEMBER或STATIC聲明在對(duì)象說明局部的子程序。方法名不能和對(duì)象類型名、屬性名重復(fù)。MEMBER方法只能通過對(duì)象實(shí)例調(diào)用,如: instance_expression.method() 但是,STATIC方法直接通過對(duì)象類型調(diào)用,而不是實(shí)例,如:object_type_name.method() 方法的定義規(guī)那么與打包子程序的相同,也分為說明和體兩個(gè)局部。說明局部由一個(gè)方法名和一個(gè)可選的參數(shù)列表組成,如果是函數(shù),還需要包含一個(gè)返回類型。包體就是一段能執(zhí)行一個(gè)特殊任務(wù)的代碼。對(duì)于對(duì)象類型說明中的每個(gè)方法說明,在對(duì)象類型體中都必須有與

18、之對(duì)應(yīng)的方法體實(shí)現(xiàn),除非這個(gè)方法是用關(guān)鍵字NOT INSTANTIABLE加以限定,它的意思就是方法體的實(shí)現(xiàn)只在子類中出現(xiàn)。為了使方法說明和方法體相匹配,PL/SQL編譯器采用token-by- token的方式把它們的頭部進(jìn)行比較。頭部必須精確匹配。與屬性相同,一個(gè)形式參數(shù)的聲明也是由名稱和數(shù)據(jù)類型組成。但是,參數(shù)的類型不能受到大小約束。數(shù)據(jù)的類型可以是任何Oracle類型,除了那些不適用于屬性的類型。這些約束也適用于返回值的類型。· 方法實(shí)現(xiàn)所允許使用的語言 Oracle允許我們?cè)赑L/SQL、Java或C語言中實(shí)現(xiàn)對(duì)象方法。我們可以在Java或C語言中實(shí)現(xiàn)類型方法,只需提供一個(gè)

19、調(diào)用說明即可。調(diào)用說明在Oracle的數(shù)據(jù)詞典中公布了Java方法或外部C函數(shù)。它把程序的名稱、參數(shù)類型和返回值信息映射到對(duì)應(yīng)的SQL中去。 · SELF參數(shù) MEMBER方法接受一個(gè)內(nèi)置的SELF參數(shù),它代表了對(duì)象類型的實(shí)例。不管顯式或隱式聲明,它總是第一個(gè)傳入MEMBER方法的參數(shù)。但是,STATIC方法就不能接受或引用SELF。 在方法體中,SELF指定了被調(diào)用方法所屬的對(duì)象實(shí)例。例如,方法transform把SELF聲明為IN OUT參數(shù): CREATE TYPE Complex AS OBJECT (  

20、MEMBER FUNCTION transform (SELF IN OUT Complex) . 我們不能把SELF指定成其他數(shù)據(jù)類型。在MEMBER函數(shù)中,如果SELF沒有聲明的話,它的參數(shù)默認(rèn)為IN。但是,在MEMBER過程中,如果SELF沒有什么,那么它的參數(shù)模式默認(rèn)為IN OUT。并且,我們不能把SELF的模式指定為OUT。 如下例所示,方法可以直接引用SELF的屬性,并不需要限定修飾詞: CREATE FUNCTION gcd(x INTEGER, y INTEG

21、ER)  RETURN INTEGER AS  - find greatest common divisor of x and y  ans   INTEGER;BEGIN  IF (y <= x) AND(x MOD y = 0) THEN    an

22、s    := y;  ELSIF x < y THEN    ans    := gcd(y, x);  ELSE    ans    := gcd(y, x MOD y);  END IF; 

23、0;RETURN ans;END;CREATE TYPE rational AS OBJECT(  num   INTEGER,  den   INTEGER,  MEMBER PROCEDURE normalize,  .);CREATE TYPE BODY rational AS  MEMBER PROCEDURE

24、 normalize IS    g   INTEGER;  BEGIN    g      := gcd(SELF.num, SELF.den);    g      := gcd(num, den);   -

25、0;equivalent to previous statement    num    := num / g;    den    := den / g;  END normalize;  .END; 如果我們從SQL語句中調(diào)用了一個(gè)空實(shí)例(即SELF為空)的MEMBER方法,方法不會(huì)被調(diào)用,并且

26、會(huì)返回一個(gè)空值。如果從過程語句調(diào)用的話,PL/SQL就會(huì)拋出預(yù)定義異常SELEF_IS_NULL。 · 重載 與打包子程序一樣,同種類型的方法(函數(shù)或過程)都能被重載。也就是說,我們可以為不同的方法起相同的名字,只要它們的形式參數(shù)在數(shù)量、順序或數(shù)據(jù)類型上有所不同。當(dāng)我們調(diào)用其中一個(gè)方法的時(shí)候,PL/SQL會(huì)把實(shí)參列表和形參列表作比較,然后找出適宜的方法。子類型也可以重載它的基類方法。這種情況下,方法必須有完全相同的形式參數(shù)。如果兩個(gè)方法只是在參數(shù)模式上不同的話,我們是不能進(jìn)行重載操作的。并且,我們不能因兩個(gè)函數(shù)的返回值類型不同而對(duì)它們進(jìn)行重載。· MAP和ORDER方法 一

27、個(gè)標(biāo)量類型,如CHAR或REAL的值都有一個(gè)預(yù)定義的順序,這樣它們之間就能進(jìn)行比較。但是對(duì)象類型的實(shí)例沒有預(yù)定義的順序。要想對(duì)它們進(jìn)行比較或排序就要調(diào)用我們自己實(shí)現(xiàn)的MAP函數(shù)。在下面的例子中,關(guān)鍵字MAP指明了方法convert()通過把Relational對(duì)象影射到REAL型上,來對(duì)它們進(jìn)行排序操作:CREATE TYPE rational AS OBJECT(  num   INTEGER,  den   INTEGER,  MA

28、P MEMBER FUNCTION CONVERT    RETURN REAL,  .);CREATE TYPE BODY rational AS  MAP MEMBER FUNCTION CONVERT    RETURN REAL IS  BEGIN    RETURN n

29、um / den;  END CONVERT;  .END; PL/SQL使用順序來計(jì)算布爾表達(dá)式的值,如x < y,并且可以在DISTINCT,GROUP BY和ORDER BY子句中作比較。MAP方法convert()可以返回一個(gè)對(duì)象在所有Relation對(duì)象中的相對(duì)位置。一個(gè)對(duì)象類型只能包含一個(gè)MAP方法,它接受一個(gè)內(nèi)置參數(shù)SELF并返回一個(gè)標(biāo)量類型:DATE、NUMBER、VARCHAR2,或是一個(gè)ANSI SQL類型,如CHARACTER或REAL。另外,我們還可以用ORDER方法。一個(gè)對(duì)象類型只能有一個(gè)OR

30、DER方法,它必須是一個(gè)能返回?cái)?shù)字結(jié)果的函數(shù)。在下面的例子中,關(guān)鍵字ORDER說明了方法match()可以對(duì)兩個(gè)對(duì)象進(jìn)行比較操作:CREATE TYPE customer AS OBJECT(  ID     NUMBER,  NAME   VARCHAR2(20),  addr   VARCHAR2(30),  ORDER MEMBER FUNC

31、TION match(c customer)    RETURN INTEGER);CREATE TYPE BODY customer AS  ORDER MEMBER FUNCTION match(c customer)    RETURN INTEGER IS  BEGIN    IF ID&#

32、160;< c.ID THEN      RETURN -1;   - any negative number will do    ELSIF ID > c.ID THEN      RETURN 1;   - any

33、0;positive number will do    ELSE      RETURN 0;    END IF;  END;END; 每個(gè)ORDER方法都只能接受兩個(gè)參數(shù):內(nèi)置參數(shù)SELF和另外一個(gè)同類型的對(duì)象。如果c1和c2是Customer對(duì)象,一個(gè)c1 > c2這樣的比較就會(huì)自動(dòng)調(diào)用方法match。該方法能夠返回負(fù)數(shù)、零或正數(shù),分別代表SELF比另外一個(gè)對(duì)象小、等或大。

34、如果傳到ORDER方法的參數(shù)任意一個(gè)為空,方法就會(huì)返回空值。知道方針:一個(gè)MAP方法就好比一個(gè)哈希函數(shù),能把對(duì)象值影射到標(biāo)量值,然后用操作符,如<、=等來進(jìn)行比較。一個(gè)ORDER方法只是簡單地將兩個(gè)對(duì)象進(jìn)行比較。我們可以聲明一個(gè)MAP方法或是一個(gè)ORDER方法,但不同時(shí)聲明這兩個(gè)方法。如果我們聲明了其中一個(gè),我們就可以在SQL或過程語句中進(jìn)行對(duì)象比較。但是,如果我們沒有聲明方法,我們就只能在SQL語句中進(jìn)行等或不等的比較。(兩個(gè)同類型的對(duì)象只有它們對(duì)應(yīng)的屬性值相同的時(shí)候才相等。)在對(duì)大量的對(duì)象進(jìn)行排序或合并的時(shí)候,可以使用一個(gè)MAP方法。一次調(diào)用會(huì)把所有的對(duì)象影射到標(biāo)量中,然后對(duì)標(biāo)量值進(jìn)

35、行排序。ORDER方法的效率相比照擬低,因?yàn)樗仨毞磸?fù)地調(diào)用(它一次只能比較兩個(gè)對(duì)象)。· 構(gòu)造方法 每個(gè)對(duì)象類型都有一個(gè)構(gòu)造方法,它是一個(gè)名稱與對(duì)象類型名稱相同的函數(shù),用于初始化,并能返回一個(gè)對(duì)象類型的新的實(shí)例。Oracle會(huì)為每個(gè)對(duì)象類型生成一個(gè)構(gòu)造函數(shù),其中形參與對(duì)象類型的屬性相匹配。也就是說,參數(shù)和屬性是一一對(duì)應(yīng)的關(guān)系,并且順序、名稱和數(shù)據(jù)類型都完全相同。我們也可以定義自己的構(gòu)造方法,要么覆蓋掉系統(tǒng)定義的構(gòu)造函數(shù),要么定義一個(gè)有著不同方法簽名的新構(gòu)造函數(shù)。PL/SQL從來不會(huì)隱式地調(diào)用構(gòu)造函數(shù),所以我們必須顯式地調(diào)用它。3、更改已存在對(duì)象類型的屬性和方法我們可以使用ALTER

36、 TYPE語句來添加、修改或刪除屬性,并可以為已存在的對(duì)象類型添加或刪除方法: CREATE TYPE person_typ AS OBJECT(  NAME      CHAR(20),  ssn       CHAR(12),  address   VARCHAR2(100);CREATE TYPE person_

37、nt IS TABLE OF person_typ;CREATE TYPE dept_typ AS OBJECT(  mgr    person_typ,  emps   person_nt);CREATE  TABLE dept OF dept_typ;- Add new attributes to Per

38、son_typ and propagate the change- to Person_nt and dept_typALTER  TYPE person_typ ADD ATTRIBUTE (picture BLOB, dob DATE)  CASCADE NOT INCLUDING TABLE DATA;CREATE TYPE mytype&#

39、160;AS OBJECT(  attr1   NUMBER,  attr2   NUMBER);ALTER  TYPE mytype ADD ATTRIBUTE (attr3 NUMBER),  DROP ATTRIBUTE attr2,  ADD ATTRIBUTE attr4 NUMBER CASCADE; 在過

40、程編譯時(shí),它總是使用當(dāng)前引用的對(duì)象類型版本。在對(duì)象類型發(fā)生改變時(shí),效勞器端引用那個(gè)對(duì)象類型的過程就變得無效了,在下次過程被調(diào)用時(shí)它會(huì)被自動(dòng)重新編譯。而對(duì)于客戶端引用被更改正的類型的過程,我們就必須手動(dòng)編譯。 如果從基類刪除一個(gè)方法,那么也必須修改覆蓋被刪除方法的子類。我們可以用ALTER TYPE的CASADE選擇來判斷是否有子類被影響到;如果有子類覆蓋了方法,那么語句就會(huì)被回滾。為了能成功地從基類刪除一個(gè)方法,我們可以: 1. 先從子類刪除方法 2. 從基類刪除方法,然后用不帶OVERRIDING關(guān)鍵字的ALTER TYPE把它重新添加進(jìn)去 六、定義對(duì)象類型對(duì)象類型可以表現(xiàn)現(xiàn)實(shí)世界中的任何實(shí)

41、體。例如,一個(gè)對(duì)象類型能表現(xiàn)學(xué)生,銀行賬戶,計(jì)算機(jī)顯示器,有理數(shù)或者是像隊(duì)列,棧,鏈表這樣的數(shù)據(jù)結(jié)構(gòu)。這一節(jié)給出了幾個(gè)完整的例子,讓我們了解如何設(shè)計(jì)對(duì)象類型并編寫我們自己的對(duì)象類型。目前我們還不能在PL/SQL塊、子程序或包中定義對(duì)象類型。但是,我們可以在SQL*Plus中用下面的語法來定義它: CREATE OR REPLACE TYPE type_name  AUTHID CURRENT_USER | DEFINER   IS | AS OB

42、JECT | UNDER supertype_name (  attribute_name datatype, attribute_name datatype.  MAP | ORDER MEMBER function_spec,  FINAL| NOT FINAL MEMBER function_spec,  INSTANTIABLE| NOT 

43、INSTANTIABLE MEMBER function_spec,  MEMBER | STATIC subprogram_spec | call_spec  , MEMBER | STATIC subprogram_spec | call_spec.) FINAL| NOT FINAL  INSTANTIABLE| NOT INSTANTIABLE;CR

44、EATE OR REPLACE TYPE BODY type_name IS | AS   MAP | ORDER MEMBER function_body;  | MEMBER | STATIC subprogram_body | call_spec;  MEMBER | STATIC subprogram_body

45、 | call_spec;.END; 1、PL/SQL類型繼承一覽PL/SQL支持單繼承模式。我們可以定義對(duì)象類型的子類型。這些子類型包括父類型(或超類)所有的屬性和方法。子類型還可以包括額外的屬性和方法,并可以覆蓋超類的方法。 我們還可以定義子類是否能繼承于某個(gè)特定的類型。我們也可以定義不能直接初始化的類型和方法,只有聲明它們的子類才可以進(jìn)行初始化操作。 有些類型屬性可以用ALTER TYPE語句動(dòng)態(tài)的改變。當(dāng)基類發(fā)生變化時(shí),無論是用ALTER TYPE語句還是重新定義基類,子類會(huì)自動(dòng)的應(yīng)用這些改變的內(nèi)容。我們可以用TREAT操作符只返回某一個(gè)指定的子類的對(duì)象。 從REF

46、和DEREF函數(shù)中產(chǎn)生的值可以代表聲明過的表或視圖類型,或是一個(gè)或多個(gè)它的子類型。 · PL/SQL類繼承舉例 - Create a supertype from which several subtypes will be derived.CREATE TYPE person_typ AS OBJECT(  ssn       NUMBER, &

47、#160;NAME      VARCHAR2(30),  address   VARCHAR2(100)NOT FINAL;- Derive a subtype that has all the attributes of the supertype,- plus some additional attributes.CREA

48、TE TYPE student_typ UNDER person_typ(  deptid   NUMBER,  major    VARCHAR2(30)NOT FINAL;- Because Student_typ is declared NOT FINAL, you can derive- further subtypes

49、 from it.CREATE TYPE parttimestudent_typ UNDER student_typ(  numhours   NUMBER);- Derive another subtype. Because it has the default attribute- FINAL, you cannot use Employee_

50、typ as a supertype and derive- subtypes from it.CREATE TYPE employee_typ UNDER person_typ(  empid   NUMBER,  mgr     VARCHAR2(30);- Define an object type t

51、hat can be a supertype. Because the- member function is FINAL, it cannot be overridden in any- subtypes.CREATE TYPE T AS OBJECT (., MEMBER PROCEDURE Print(), FINAL M

52、EMBERFUNCTION foo(x NUMBER).) NOT FINAL;- We never want to create an object of this supertype. By using- NOT INSTANTIABLE, we force all objects to use one of the

53、0;subtypes- instead, with specific implementations for the member functions.CREATE TYPE Address_typ AS OBJECT(.) NOT INSTANTIABLE NOT FINAL;- These subtypes can provide their own implem

54、entations of- member functions, such as for validating phone numbers and- postal codes. Because there is no "generic" way of doing these- things, only objects of

55、0;these subtypes can be instantiated.CREATE TYPE USAddress_typ UNDER Address_typ(.);CREATE TYPE IntlAddress_typ UNDER Address_typ(.);- Return REFs for those Person_typ objects that are instances&

56、#160;of- the Student_typ subtype, and NULL REFs otherwise.SELECT TREAT(REF(p) AS REF student_typ)  FROM person_v p;- Example of using TREAT for assignment.- Return REFs for th

57、ose Person_type objects that are instances of- Employee_type or Student_typ, or any of their subtypes.SELECT REF(p)  FROM person_v p WHERE VALUE(p) IS OF(employee_typ, student_typ)

58、;- Similar to above, but do not allow any subtypes of Student_typ.SELECT REF(p)  FROM person_v p WHERE VALUE(p) IS OF(ONLY student_typ);- The results of REF and DERE

59、F can include objects of Person_typ- and its subtypes such as Employee_typ and Student_typ.SELECT REF(p)  FROM person_v p;SELECT DEREF(REF(p)  FROM person_v p; 2、對(duì)象類型實(shí)例:棧棧是一個(gè)有序集合。棧有一個(gè)棧頂

60、和一個(gè)棧底。棧中的每一項(xiàng)都只能在棧頂添加或刪除。所以,最后一個(gè)被參加棧的項(xiàng)會(huì)被最先刪除。(可以把棧想象成自助餐廳中的盤子。)壓棧和退棧操作能夠?qū)_M(jìn)行后進(jìn)先出(LIFO)更新。 棧能應(yīng)用在很多地方。例如,它們可以用在系統(tǒng)編程中控制中斷優(yōu)先級(jí)并對(duì)遞歸進(jìn)行管理。最簡單的棧實(shí)現(xiàn)就是使用整數(shù)數(shù)組,數(shù)組的一端代表了棧頂。 PL/SQL提供了VARRAY數(shù)據(jù)類型,它能讓我們聲明變長數(shù)組。要聲明變長數(shù)組屬性,必須先定義變長數(shù)組類型。但是,我們不能再對(duì)象說明中定義類型,所以,我們只能單獨(dú)的定義變長數(shù)組類型,并指定它的最大長度,具體實(shí)現(xiàn)如下: CREATE TYPE IntArray

61、0;AS VARRAY(25) OF INTEGER; 現(xiàn)在我們可以編寫對(duì)象類型說明了:CREATE TYPE stack AS OBJECT(  max_size   INTEGER,  top        INTEGER,  POSITION   intarray,  MEMBER PROCE

62、DURE initialize,  MEMBER FUNCTION FULL    RETURN BOOLEAN,  MEMBER FUNCTION empty    RETURN BOOLEAN,  MEMBER PROCEDURE push(n IN INTEGER),  MEMBER PROCEDURE 

63、;pop(n OUT INTEGER); 最后,我們可以編寫對(duì)象類型體:CREATE TYPE BODY stack AS  MEMBER PROCEDURE initialize IS  BEGIN    top         := 0;    /* Call co

64、nstructor for varray and set element 1 to NULL. */    POSITION    := intarray(NULL);    max_size    := POSITION.LIMIT;   - get varray s

65、ize constraint    POSITION.EXTEND(max_size - 1, 1);   - copy element 1 into 2.25  END initialize;  MEMBER FUNCTION FULL    RETURN BOOLEAN IS  BEG

66、IN    RETURN(top = max_size);   - return TRUE if stack is full  END FULL;  MEMBER FUNCTION empty    RETURN BOOLEAN IS  BEGIN    RE

67、TURN(top = 0);   - return TRUE if stack is empty  END empty;  MEMBER PROCEDURE push(n IN INTEGER) IS  BEGIN    IF NOT FULL THEN    

68、;  top              := top + 1;   - push integer onto stack      POSITION(top)    := n;    ELSE

69、   - stack is full      raise_application_error(-20211, 'stack overflow');    END IF;  END push;  MEMBER PROCEDURE pop(n OUT INTEGER) IS  

70、;BEGIN    IF NOT empty THEN      n      := POSITION(top);      top    := top - 1;   - pop integer off

71、0;stack    ELSE      - stack is empty      raise_application_error(-20212, 'stack underflow');    END IF;  END pop;END; 在成員過程push和pop中,我們使用內(nèi)置過程rais

72、e_application_error來關(guān)聯(lián)用戶定義的錯(cuò)誤消息。這樣,我們就能把錯(cuò)誤報(bào)告給客戶端程序而防止把未控制異常傳給主環(huán)境。客戶端程序捕獲PL/SQL異常后,可以在OTHERS異常控制句柄中用SQLCODE和SQLERRM 來確定具體的錯(cuò)誤信息。下例中,當(dāng)異常被拋出時(shí),我們就把對(duì)應(yīng)的錯(cuò)誤消息輸出: DECLARE  .BEGIN  .EXCEPTION  WHEN OTHERS THEN    dbms_output.put_line(SQLERRM);END; 另外,

73、程序還可以使用編譯指示EXCEPTION_INIT把raise_application_error返回的錯(cuò)誤編號(hào)影射到命名異常中,如下例所示:DECLARE  stack_overflow    EXCEPTION;  stack_underflow   EXCEPTION;  PRAGMA EXCEPTION_INIT(stack_overflow, -20211);  PRAGMA EXCEPTION_INIT(

74、stack_underflow, -20212);BEGIN  .EXCEPTION  WHEN stack_overflow THEN  .END; 3、對(duì)象類型實(shí)例:售票處假設(shè)有一個(gè)連鎖電影院,每個(gè)影院有三個(gè)銀幕。每個(gè)影院有一個(gè)售票處,銷售三種不同電影的影票。所有影票的價(jià)格都為三美元。定期檢查影票的銷售情況,然后及時(shí)補(bǔ)充影票。 在定義代表銷售處的對(duì)象類型之前,我們必須考慮到必要的數(shù)據(jù)和操作。對(duì)于一個(gè)簡單的售票處來說,對(duì)象類型需要票價(jià)、當(dāng)前影票存量和已售影票的收據(jù)這些屬性。它還需要一些方法:購票、盤存、

75、補(bǔ)充存量和收集收據(jù)。 對(duì)于收據(jù),我們可以使用含有三個(gè)元素的數(shù)組。元素1、2和3各自記錄電影1、2和3。要聲明一個(gè)變長數(shù)組屬性,我們就必須先像下面這樣定義它的類型: CREATE TYPE RealArray AS VARRAY(3) OF REAL; 現(xiàn)在,我們可以編寫對(duì)象類型說明: CREATE TYPE ticket_booth AS OBJECT(  price         R

76、EAL,  qty_on_hand   INTEGER,  receipts      realarray,  MEMBER PROCEDURE initialize,  MEMBER PROCEDURE purchase(movie INTEGER, amount REAL, CHANGE OUT REAL), &#

77、160;MEMBER FUNCTION inventory    RETURN INTEGER,  MEMBER PROCEDURE replenish(quantity INTEGER),  MEMBER PROCEDURE COLLECT(movie INTEGER, amount OUT REAL); 最后,我們可以編寫對(duì)象類型體: CREATE TYPE BODY

78、60;ticket_booth AS  MEMBER PROCEDURE initialize IS  BEGIN    price          := 3.00;    qty_on_hand    := 5000;   - prov

79、ide initial stock of tickets    - call constructor for varray and set elements 1.3 to zero    receipts       := realarray(0, 0, 0); 

80、60;END initialize;  MEMBER PROCEDURE purchase(movie INTEGER, amount REAL, CHANGE OUT REAL) IS  BEGIN    IF qty_on_hand = 0 THEN      raise_application_error(-20

81、213, 'out of stock');    END IF;    IF amount >= price THEN      qty_on_hand        := qty_on_hand - 1;   

82、60;  receipts(movie)    := receipts(movie) + price;      CHANGE             := amount - price;    ELSE   -

83、0;amount is not enough      CHANGE    := amount;   - so return full amount    END IF;  END purchase;  MEMBER FUNCTION inventory &#

84、160;  RETURN INTEGER IS  BEGIN    RETURN qty_on_hand;  END inventory;  MEMBER PROCEDURE replenish(quantity INTEGER) IS  BEGIN    qty_on_hand    :=

85、0;qty_on_hand + quantity;  END replenish;  MEMBER PROCEDURE COLLECT(movie INTEGER, amount OUT REAL) IS  BEGIN    amount             :=&

86、#160;receipts(movie);   - get receipts for a given movie    receipts(movie)    := 0;   - reset receipts to zero  END COLLECT;END; 4、對(duì)象類型實(shí)例:銀行賬戶在定義銀行賬戶對(duì)象類型之前,我們必

87、須考慮一下要使用的數(shù)據(jù)和操作。對(duì)于一個(gè)簡單的銀行賬戶來說,對(duì)象類型需要一個(gè)賬號(hào)、余額和狀態(tài)這三個(gè)屬性。所需的操作有:翻開帳戶,驗(yàn)證賬號(hào),關(guān)閉賬戶,存款,取款和余額結(jié)算。首先,我們要像下面這樣編寫對(duì)象類型說明: CREATE TYPE bank_account AS OBJECT(  acct_number   INTEGER(5),  balance       REAL,  status

88、0;       VARCHAR2(10),  MEMBER PROCEDURE OPEN(amount IN REAL),  MEMBER PROCEDURE verify_acct(num IN INTEGER),  MEMBER PROCEDURE CLOSE(num IN INTEGER, amount OUT 

89、;REAL),  MEMBER PROCEDURE deposit(num IN INTEGER, amount IN REAL),  MEMBER PROCEDURE withdraw(num IN INTEGER, amount IN REAL),  MEMBER FUNCTION curr_bal(num IN INTEGER)  

90、  RETURN REAL); 然后編寫對(duì)象體: CREATE TYPE BODY bank_account AS  MEMBER PROCEDURE OPEN(amount IN REAL) IS  - open account with initial deposit  BEGIN    IF NOT a

91、mount > 0 THEN      raise_application_error(-20214, 'bad amount');    END IF;    SELECT acct_sequence.NEXTVAL      INTO acct_number   

92、   FROM DUAL;    status     := 'open'    balance    := amount;  END OPEN;  MEMBER PROCEDURE verify_acct(num IN INTEGER) IS 

93、; - check for wrong account number or closed account  BEGIN    IF (num <> acct_number) THEN      raise_application_error(-20215, 'wrong number');    ELSIF(status = 'closed') THEN      ra

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論