객체 타입- 3

    객체 타입의 상속

    객체 타입은 상속을 지원한다. 객체 타입의 상속에는 키워드 UNDER를 사용한다.

    -- person_type을 상속한 employee_type 명세
    CREATE OR REPLACE TYPE employee_type UNDER person_type(
    	-- person_type를 상속하여 employee_type 정의
       empno	NUMBER(4),		--사번
       sal		NUMBER(7,2),	--급여
       deptno	NUMBER(2),		--부서 번호
       mgr		REF employee_type -- 상급자 로우에 대한 논리적 포인터
    );

    상속되기를 바라는 모든 슈퍼타입은 NOT FINAL 키워드를 사용하여 상속이 가능함을 명시해야 한다.

    기본은 FINAL인데, NOT FINAL을 명시하지 않은 객체 타입은 상속될 수 없다. 위 예제처럼 employee_type이 person_type을 상속받으려면 먼저 person_type에 다음과 같이 NOT FINAL을 지정해야 한다.

    CREATE OR REPLACE TYPE person_type AS OBJECT(
    	family_name VARCHAR2(30),	-- 성
        ...
    ) NOT FINAL /* 상속 허용 */	;

    메소드의 경우에도 NOT FINAL을 지정할 수 있는데, 이 경우의 NOT FINAL은 해당 메소드가 서브타입에서 재정의(Override)될 수 있음을 의미한다. 슈퍼타입에서 FINAL을 지정한 메소드는 서브타입에서 재정의될 수 없다. 타입과 메소드에 대한 FINAL/NOT FINAL을 정리하면 다음과 같다.

    • 타입: 기본값은 FINAL이다. NOT FINAL을 지정한 타입만이 상속될 수 있다.
    • 메소드: 기본값은 NOT FINAL이다. FINAL을 지정한 메소드는 상속이 금지된다.

    메소드의 재정의

    서브타입의 메소드 재정의(Override)는 슈퍼타입에서 정의된 메소드를 서브타입에서 변경하여 슈퍼타입과는 다른 행위를 하도록 하는 것을 말한다. 서브타입에서 메소드를 재정의할 때에는 슈퍼타입에서 선언된 메소드 프로토타입과 완전히 동일한 프로토타입으로 선언해야 한다.(공백과 대소문자 차이 빼고는 모두 동일해야 한다.) 슈퍼타입의 메소드와 프로토타입이 달라지면 다른 메소드가 되거나 재정의가 아닌 중복 정의가 된다. 메소드의 재정의 시에는 OVERRIDING 키워드를 사용한다.

    -- 메소드 재정의 명세
    CREATE OR REPLACE TYPE employee_type UNDER person_type(	-- person_type을 상속
    	empno NUMBER(4),	-- 사번
        sal	  NUMBER(7,2),	-- 급여
        deptno NUMBER(2),	-- 부서 번호
        mgr   REF employee_type, -- 상급자 로우에 대한 논리적 포인터
        
        OVERRIDING MEMBER FUNCTION display RETURN VARCHAR2	-- person_type의 display를 재정의
    );
    -- 메소드 재정의 본체
    CREATE OR REPLACE TYPE BODY employee_type
    AS
    	-- person_type의 display를 재정의
        OVERRIDING MEMBER FUNCTION display RETURN VARCHAR2
        IS
        BEGIN
        	-- 슈퍼타입의 메소드는 (SELF AS 슈퍼타입명). 을 접두어로 하여 호출한다.
            RETURN (SELF AS person_type).display ||', 사번:'|| empno ||
            		', 급여:'|| NVL(sal, 0)|| ', 부서 번호:' || deptno;
        END;
    END;

    위 예제는 재정의된 멤버 함수 display를 정의하는 객체 타입 본체다. person_type의 display는 해당 타입의 네 속성을 하나의 문자열로 묶어서 반환하는 데 비해, 재정의된 버전은 여기에 employee_type의 네 가지 추가 속성 중에서 사번, 급여, 부서 번호를 포함하여 일곱 개를 연결해 반환하도록 재정의되었다.

     

    -- 메소드 재정의 본체
    CREATE OR REPLACE TYPE BODY employee_type
    AS
    	-- person_type의 display를 재정의
        OVERRIDING MEMBER FUNCTION display RETURN VARCHAR2
        IS
        BEGIN
        	-- 슈퍼타입의 메소드는 (SELF AS 슈퍼타입명). 을 접두어로 하여 호출한다.
            RETURN (SELF AS person_type).display ||', 사번:'|| empno ||
            		', 급여:'|| NVL(sal,0) || ', 부서 번호:' || deptno;
        END;
    END;

    예제에서 특이한 부분이 있는데, 바로 (SELF AS person_type)이다. 이 부분은 일반화된 호출(Generalized Invocation)이라고 부른다. 일반화된 호출은 서브타입에서 슈퍼타입의 메소드를 호출하기 위해 사용된다.

    일반화된 호출의 형식은 다음과 같다.

    (객체 인스턴스 AS 슈퍼타입명).메소드

    일반화된 호출과 유사한 것으로 일반화된 표현식(Generalized Expression)이 있다. 일반화된 호출은 인스턴스를 슈퍼타입으로 변환하여 메소드를 호출한다. 반면에 일반화된 표현식은 매개변수 SELF를 슈퍼타입으로 변환 후 슈퍼타입의 메소드를 호출하는 방식을 사용한다. 일반화된 표현식의 형식은 다음과 같다.

    슈퍼타입명.메소드(객체인스턴스 AS 슈퍼타입명)
    -- 재정의된 메소드 사용
    DECLARE
    	v_emp employee_type := employee_type('홍', '길동', '청학동', '일번지',
        									1000, 9900, 10, NULL) ;
    BEGIN
    	DBMS_OUTPUT.PUT_LINE(v_emp.display);			-- employee_type의 display 호출
        DBMS_OUTPUT.PUT_LINE((v_emp AS person_type).display );  -- person_type의 display 호출
        DBMS_OUTPUT.PUT_LINE(person_type.display((v_emp AS person_type)));	-- person_type의 display 호출
    END    

    위 예제는 앞서 재정의된 메소드를 호출하는 것을 보여준다. 각각 display 메소드를 서로 다른 방식으로 호출한다.

    5번 줄에서는 employee_type 타입의 변수 v_emp를 사용하여 v_emp.display를 호출하므로 employee_type의 메소드가 호출된다. 6번 줄에서는 일반화된 호출을 위해 (v_emp AS person_type)을 사용하여 명시적으로 person_type.display를 호출한다. 7번 줄은 일반화된 표현식을 사용하여 person_type.display를 호출하는데, 변수명.메소드가 아닌 객체타입.메소드를 사용하면서 첫 번째 매개변수인 SELF를 명시적으로 제공하는 방법을 사용했다.

    성:홍, 이름:길동, 기본 주소:청학동, 상세 주소:일번지, 사번: 1000, 급여:9900, 부서 번호:10
    성:홍, 이름:길동, 기본 주소:청학동, 상세 주소:일번지
    성:홍, 이름:길동, 기본 주소:청학동, 상세 주소:일번지

    예제의 실행결과는 다음과 같다. 예제의 6번 줄과 7번 줄이 동일하게 메소드 person_type.display를 호출하기 떄문에 출력이 동일함을 알 수 있다.

     

    메소드의 중복정의

    메소드의 중복 정으(Overloading)는 패키지에서 서브프로그램을 중복 정의하는 것과 마찬가지로 동일한 이름을 가지는 메소드를 매개변수의 개수, 순서, 데이터 타입을 달리하여 정의하는 것을 말한다.

    CREATE OR REPLACE TYPE employee_type UNDER person_type(	 -- person_type을 상속
    	empno	 NUMBER(4),		--사번
        sal		 NUMBER(7,2)	--급여
        deptno	 NUMBER(2),		--부서 번호
        mgr		 REF employee_type,  -- 상급자 로우에 대한 논리적 포인터
        
        MEMBER FUNCTION gross_sal RETURN VARCHAR2,			-- 급여 총액 Method 1
        MEMBER FUNCTION gross_sal(a_incentive number) RETURN VARCHAR2	-- 급여 총액 Method 2
    );
    /
    
    CREATE OR REPLACE TYPE BODY employee_type
    AS
    	-- 중복 정의 1: 사원의 급여를 반환
        MEMBER FUNCTION gross_sal RETURN VARCHAR2
        IS
        BEGIN
        	RETURN NVL(sal, 0);
        END;
        
        -- 중복 정의 2: 사원의 급여 + 인센티브를 반환
        MEMBER FUNCTION gross_sal(a_incentive number) RETURN VARCHAR2
        IS
        BEGIN
        	RETURN NVL(sal, 0) + NVL(a_incentive, 0);
        END;
    END;
    /

    메소드 gross_sal은 두가지 버전으로 중복 정의되었다. 첫 번째 버전은 매개변수가 없는데, 속성 sal에 저장된 값을 반환한다. 두 번째 버전은 속성 sal 값에 매개변수로 제공되는 인센티브를 더한 값을 반환한다.

    'DATABASE > SQL, PL-SQL' 카테고리의 다른 글

    객체 타입 - 5  (0) 2021.05.19
    객체 타입 - 4  (0) 2021.05.09
    Object Type(객체 타입) - 2  (0) 2021.04.29
    Object Type(객체 타입) - 1  (0) 2021.04.17
    Trigger(트리거)  (0) 2021.04.14

    댓글