2016年3月12日 星期六

物件導向一(屬性、方法、建構子) (PL/SQL 二十八)

※屬性、方法

※宣告

CREATE OR REPLACE TYPE xxx_emp IS OBJECT(
    xxx_empno NUMBER(4),
    xxx_sal NUMBER(7,2),
    xxx_deptno NUMBER(2),
    MEMBER PROCEDURE update_sal(v_percent NUMBER),
    STATIC PROCEDURE update_sal(v_deptno NUMBER, v_percent NUMBER),
    MEMBER FUNCTION get_sal RETURN NUMBER,
    STATIC FUNCTION get_sal(v_empno NUMBER) RETURN NUMBER
) NOT FINAL;

※一定要宣告屬性,但可以沒有方法

※宣告了3個屬性和4個方法;方法又分成兩個靜態方法和兩個一般方法

※TYPE的型態不能使用%TYPE之類的語法

※MEMBER的NUMBER不能用NUMBER(2),可能括號會誤判吧


※實作

CREATE OR REPLACE TYPE BODY xxx_emp IS
    MEMBER PROCEDURE update_sal(v_percent NUMBER) IS
    BEGIN
        UPDATE EMP SET SAL = SAL * (1 + v_percent)
        WHERE EMPNO = SELF.xxx_empno;
    END;
    
    STATIC PROCEDURE update_sal(v_deptno NUMBER, v_percent NUMBER) IS
    BEGIN
        UPDATE EMP SET SAL = SAL * (1 + v_percent)
        WHERE DEPTNO = v_deptno;
    END;
    
    MEMBER FUNCTION get_sal RETURN NUMBER IS
        ooo_sal_comm NUMBER;
    BEGIN
        SELECT SAL + NVL(COMM, 0) INTO ooo_sal_comm FROM EMP
        WHERE EMPNO = SELF.xxx_empno;
        RETURN ooo_sal_comm;
    END;
    
    STATIC FUNCTION get_sal(v_empno NUMBER) RETURN NUMBER IS
        ooo_sal_comm NUMBER;
    BEGIN
        SELECT SAL + NVL(COMM, 0) INTO ooo_sal_comm FROM EMP
        WHERE EMPNO = v_empno;
        RETURN ooo_sal_comm;
    END;
END;

※實作時,將整個方法複製過來,將TYPE改成TYPE BODY,然後Object()不要,最後變END,而且只要實作方法即可,屬性不用

※靜態的方法不能使用SELF關鍵字,相當於java的this

※最後的END不能寫END xxx_update_emp

※可以在圖中看到TYPE和TYPE BODY



※測試

DECLARE
    ooo_emp xxx_emp;
BEGIN
    ooo_emp := xxx_emp(7521, 1250, 30);
    ooo_emp.xxx_sal := 2000;
    DBMS_OUTPUT.PUT_LINE(ooo_emp.xxx_sal);
    
    DBMS_OUTPUT.PUT_LINE('修改前:' || ooo_emp.get_sal());
    DBMS_OUTPUT.PUT_LINE('靜態修改前:' || xxx_emp.get_sal(7499));
    
    ooo_emp.update_sal(0.2);
    DBMS_OUTPUT.PUT_LINE('修改後:' || ooo_emp.get_sal());
    
    xxx_emp.update_sal(30, 0.2);
    DBMS_OUTPUT.PUT_LINE('靜態修改後:' || xxx_emp.get_sal(7499));
END;

※和java一樣,要呼叫靜態方法時,要用「類別.方法」

※2000那行只有在顯示有用,並沒有真的存到資料庫

※如果要刪除類別,指令要下「DROP TYPE xxx_emp;」



※建構子

※宣告

CREATE OR REPLACE TYPE xxx_constructor IS OBJECT(
    xxx_empno NUMBER(4),
    xxx_sal NUMBER(7,2),
    xxx_deptno NUMBER(2),
    
    CONSTRUCTOR FUNCTION xxx_constructor(p_empno NUMBER) 
    RETURN SELF AS RESULT,
    
    CONSTRUCTOR FUNCTION xxx_constructor(p_empno NUMBER, p_deptno NUMBER) 
    RETURN SELF AS RESULT
) NOT FINAL;

※寫了兩個建構子,但其實還有一個是傳3個參數的,也就是宣告的3個屬性,這也是一個建構子

※沒有CONSTRUCTOR PROCEDURE這種語法


※實作

CREATE OR REPLACE TYPE BODY xxx_constructor IS
    CONSTRUCTOR FUNCTION xxx_constructor(p_empno NUMBER) 
    RETURN SELF AS RESULT IS
    BEGIN
        SELF.xxx_empno := p_empno;
        SELECT SAL INTO SELF.xxx_sal FROM EMP
        WHERE EMPNO = p_empno;
        RETURN;
    END;
    
    CONSTRUCTOR FUNCTION xxx_constructor(p_empno NUMBER, p_deptno NUMBER) 
    RETURN SELF AS RESULT IS
    BEGIN
        SELF.xxx_empno := p_empno;
        SELF.xxx_sal := 1500;
        SELF.xxx_deptno := p_deptno;
        RETURN;
    END;
END;

※一定要寫RETURN,雖然編譯會過,但呼叫時,會出「ORA-06503: PL/SQL: 函數沒有傳回任何值」的錯


※測試

DECLARE
    ooo_cons1 xxx_constructor;
    ooo_cons2 xxx_constructor;
    ooo_cons3 xxx_constructor;
BEGIN
    ooo_cons1 := xxx_constructor(7521, 1250, 30);
    ooo_cons2 := xxx_constructor(7499);
    ooo_cons3 := xxx_constructor(7654, 30);
    
    DBMS_OUTPUT.PUT_LINE(ooo_cons1.xxx_sal);
    DBMS_OUTPUT.PUT_LINE(ooo_cons2.xxx_sal);
    DBMS_OUTPUT.PUT_LINE(ooo_cons3.xxx_sal);
END;


沒有留言:

張貼留言