본문 바로가기

JAVA/OOP

추상클래스

반응형

추상클래스


추상클래스 정의

- 추상클래스는 서로 다른 유형의 클래스들 간에 공통된 행위를 추출하여 정의한 가상의 클래스이다.

공통된 행위들에 대해 일반화시켜 만들었기 때문에 추상 클래스도 상속 구조를 취하게 된다.

그리고 일반화 시킨 클래스가 추상 클래스이기 때문에 추상 클래스는 상속 구조에서 슈퍼 클래스에 해당한다.

이에 반해 추상클래스의 하위 클래스들을 구체화 클래스(Concrete Class)라고 한다.


추상 클래스는 원래 클래스로 존재한 것이 아니라 여러 클래스들 간에 공통 행위들이 있어서 중복성을 배제하기 위해 일반화 시킨 클래스이기 때문에 실제 객체로 생성할 수 없다.

따라서 상속구조에서 객체를 생성할 수 잇는 슈퍼 클래스와 구별하기 위해 추상클래스를 별도로 구분하여 정의하고 있다.

예) Payment(결제) 클래스는 그 자체로서 Payament 객체가 존재하는 것이 아닌 추상 클래스로 하위클래스인 CreditCard, Cash, Point 등이 실제 객체를 생성하는 클래스


그리고 추상 클래스에 정의된 공통된 함수명만 존재하고 함수의 구현은 존재하지 않는 가상의 함수들이다.

이는 각각의 함수 내의 알고리즘(로직)이 다르게 구현된다.

즉, 하위 클래스에서 각각 자신의 방법대로 해당 함수들을 구현하게 된다. 따라서 슈퍼 클래스인 추상 클래스에는 함수 선언만 하기 때문에 추상 혹은 가상함수로 정의한다.그리고 하위 클래스에서는 이러한 추상 함수들을 실제 구현하기 때문에 추상함수가 아닌 일반함수로 정의하는 것이다.


추상클래스는 2가지 목적

1. 서로 다른 클래스들이 공통적으로 구현된 함수들에 대해 공통된 행위를 추출하기 위함.

2. 추상 클래스로부터 서브 클래싱된 모든 클래스에 대해 단일의 공통 인터페이스를 생성하기 위함.


서비 클래스마다 서로 다르게 구현된 함수들에 대한 템플릿 만을 제공하기 위함이다. 이러한 공통 인터페이스를 정의함으로써 서로 다른 타입들로 대해 서로 다르게 구현할 수 있도록 한다.

그리고 이렇게 다르게 구현된 하위 클래스들의 함수가 공통 인터페이스를 통해 외부 서비스를 제공할 수 있는 동적 바인딩 매커니즘을 통해 가능하다.


예) Order 클래스에서 Payment 클래스에 결제를 요청시 Order 클래스는 Payment 클래스의 하부 클래스들에게 직접 pay()함수를 요청할 필요없이, Payment 클래스의 processPayment(Payment p)함수만 호출하고, 매개변수로 결제할 결제객체(신용카드, 현금, 포인트)만 넘겨주면, 해당 객체에 따라 동적으로 바인딩되어 결제 함수가 이루어진다.


processPayment(Payment p) {

p.pay()

}


추상클래스 안에 하위 클래스들이 공통적으로 갖는 함수(구현된 함수)뿐만 아니라 하위클래스마다 서로 구현된 함숟르에 대한 템플릿 즉, 가상 함수를 적어도 하나 이상 지니고 있다.

이 가상 함수는 추상 클래스의 하위 클래스들에서 각자 함수의 몸체를 구현해야 한다.

pay()라는 함수는 Payment 추상클래스에서 몸체가 없지만, 하위 클래스 각각에서는 자신만의 결제 로직이 구현되어 정의되어 있어야 한다.

또한 추상클래스는 이처럼 가상 함수가 존재하기 때문에 추상클래스는 일반 다른 클래스와 달리 객체를 생성할 수 없다.


추상클래스의 특성


1. 재사용성을 높일 수 있다.

- 추상 클래스도 상속 구조를 기반으로 하기 때문에 추상 클래스에 하위 클래스들이 갖는 공통된 속성이나 함수들을 추출함으로써 재사용성을 높일 수 있다.


2. 서브 클래스 객체들을 추상클래스 객체로 대치시킬 수 있다.

- 상속구조와 마찬가지로 추상클래스와 서브 클래스 간의 관계도 is - a 관꼐가 성립된다.

즉, 서브 클래스면서 추상클래스이다.(서브 클래스 = 추상클래스)라는 관계가 성립된다.

따라서 추상 클래스 객체 대신에 서브 클래스 객체들이 대치될 수 있다.


addProduct(Product p)이라는 함수가 있다.

이 함수는 상품을 등록하는 함수로서, 이 함수의 매개변수는 추상클래스 Product 타입 객체 P로 선언되어 있다.

Product클래스는 추상클래스이기 때문에 객체를 생성할 수 없다.

그런데 이렇게 선언이 가능한 이유는 is - a 관계때문이다.

즉, Product 타입의 객체 p가 선언되었지만 p에도 Product 객체가 아닌 Product의 하위 클래스인 TV, Audio, Oven 등의 객체들이 대치된다.

이것이 바로 is - a 관계로 인해 이루어지는 대치성이다.

만일 이 대치성이 없다면 하위 클래스 별로 addProduct()이라는 함수가 각각 존재해야 한다.

그러나 대치성으로 인해 추상클래스인 슈퍼 클래스 한곳에 한번만 정의해도 하위 클래스의 객체 누구나 다 가능하게 된것이다.

이는 코드의 재사용성 뿐만 아니라 프로그램 복잡도의 간결화를 가져다 준다.


3. 서로 다른 종류의 객체들을 수집할 수 있다.

- 이기종 객체를 수집하는 Java 코드 형태로 Product 클래스에서 Product[] pList = new Product[3]; 부분이 이기종 객체들을 수집하는 코드이다.

즉, pList[3]이라는 배열에는 Product 객체가 아닌 Product의 서로 다른 하위 클래스 객체들이 들어갈 수 있다.

즉 pList에는 TV객체, Audio객체, Oven 객체가 들어가 있을 수 있다.

이러한 이유로 서로 다른 종류 즉, 이기종 객체들을 수집할수 있다는 것이다.

이 특성의 이점은 코드의 간결성을 높여준다.

displayAllProducts()라는 함수로 p[i].display()라는 메서들 호출한다.

여기서 p[i]에는 서로 다른 객체들이 있기 때문에 그때 그때 p[i]에 있는 객체에 따라 display()하는 함수의 내용이 다르게 나타난다.

만일 이러한 이기종 객체 수집 장치가 없었으면, Product[] 배열에 있는 Product의 개수만큼 display()를 반복하여 정의해야 한다. 그러나 코드 한줄로 Product의 개수만큼을 모두 커버하고 있다.

즉, 코드의 효율성과 간결성이 높아진 것이다.


public class Product {

Product[] pList = new Product[3];

static void dispalyAllProducts(product[] p) {

for(int i=0; i<p.length; i++) {

p[i].display();

}

}

}


4. 유지보수성을 향상시킬수 있다.

- 추상클래스의 경우 가상함수가 있기 때문에 하위 클래스에서는 이 가상 함수에 대한 자신의 알고리즘 혹은 로직대로 언제든지 추상클래스에 있는 함수에 영향을 주지 않고 수정이 가능하다.


5. 확장성을 높일 수 있다.

- 추상클래스는 서로 다른 유형의 하위 클래스들 간의 공통된 행위들을 추출하여 정의하기 때문에 그러한 공통 행위를 갖는 새로운 클래스를 추가하기가 매우 용이하다. 그리고 하위 클래스들이 각기 구현은 다르지만 동일한 함수 시그너처를 갖는 경우는 새로운 가상 함수를 추상클래스에 정의하면 된다.


UML


<<abstract>> 라는 스테레오 타입을 명시


'abstract' 예약어를 사용하여 'Payment' 클래스가 추상 클래스라는 것을 정의하며, 함수 앞에 'abstract' 예약어를 사용하여 pay()함수가 추상함수임을 구현한다.

추상함수는 함수에 대한 정의(시그니처:함수명, 결과타입, 입력파라미터)만 있으며 구현 내용이 없는 것을 의미한다.

이러한 pay() 추상함수는 구체화 클래스인 Cash, CreditCard, Point 구체화 클래스의 구현함수에서 구현한다.


추상클래스와 구체화 클래스의 객체생성으로 추상화 클래스는 추상함수를 포함하고 있는 불안전한 클래스로서 객체 생성시 오류가 발생, 추상함수를 구현한 구체화 클래스들은 완전한 클래스로 객체를 생성할 수 있다.


Payment payment = new Payement(); //오류

Cash cash = new Cash();

CreditCard creditCard = new CreditCard();

Point point = new Point();


Payament 추상클래스에서 단일 인터페이스를 위해 클래스 함수(static) processPayment()를 제공한다.

본 단일 인터페이스르 통해 Payment 클래스를 상속받는 CreditCard, Cash, Point와 같이 이기종의 클래스들을 입력받을 수 있다.

pay()함수는 Payment 추상클래스를 상속받는 서버 클래스에서 반드시 구현해야 하는 추상함수이다.

따라서 서브클래스들은 추상함수를 구현한 동일한 함수들을 갖기고 있다.


public abstract class Payment {

public static void processPayment(Payment p) {

p.pay();

}

public abstract void pay();

}



public class CreditCard extends Payment {

public void pay() {

System.out.println("CreditCard Payment");

}

}

public class Cash extends Payment {

public void pay() {

System.out.println("Cash Payment");

}

}

public class Point extends Payment {

public void pay() {

System.out.println("Point Payment");

}

}


Order클래스는 다양한 지불방식을 처리하기 위해서 Payment 클래스의 단일 인터페이스인 processPayment(Payment p)를 사용하고 있다.

단일 인터페이스의 입력 데이터로 CreditCard, Cash, Point 중 어떠한 클래스가 입력되더라도 인터페이스는 동일하게 사용할 수 있다.


public lass Order {

public void processOrder() {

Payment creditCard = new CreditCard();

payment.processPayment(creditCard);

}


public static void main(String args[]) {

Order order = new Order();

order.processOrder();

}

}



추상함수의 개념

- 함수의 시그니처(Signature)만 존재하며 함수 구현부가 없는 함수

- 추상클래스내에 정의된 함수

- 자식 클래스에 반드시 구현되어야 하는 함수


자바에서의 추상함수

- 함수 앞에 'abstract' 키워드를 붙임

abstract class Test {

abstract void testFun(int a);

}

-인터페이스 내에도 정의될 수 있음

(인터페이스에서는 'abstract' 생략)


C++에서의 추상함수

- 함수 앞에 virtual 키워드 붙임

- 함수뒤에 0을 붙임

- 순수가상함수라고 함.


class Test {

public:

virtual void testFun( int a) = 0;

}


정리

-추상 클래스는 서로 다른 유형의 클래스들의 공통된 행위를 추출하여 정의한 것이다.

-추상 클래스는 단일의 인터페이스를 제공한다.

-추상 클래스는 적어도 하나 이상의 가상 함수를 가져야 한다.

-추상 클래스를 이용하면 재사용성을 높여준다.

-추상 클래스를 이용하면 서비 클래스 객체들을 추상 클래스 객체들로 대치시킬 수 있다.

-추상 클래스를 이용하면 서로 다른 종류의 객체들을 수집할 수 있다.

-추상 클래스를 이용하면 유지보수성을 향상시켜준다.

-추상 클래스를 이용하면 확장성을 높여준다.

-UML에서는 클래스 <<abstract>>라는 스테레오 타입을 명시하여 해당 클래스가 추상클래스임을 정의한다.

-Java 언어에서는 'abstract' 키워드를 이용하여 추상 클래스를 구현한다.

-Java에서 추상클래스는 객체를 생성할 수 없다.

-Java에서 추상 클래스는 하나 이상의 추상함수을 가져야 한다.


출처-UML과 JAVA로 배우는 객체지향 설계 및 구현


반응형

'JAVA > OOP' 카테고리의 다른 글

다형성  (0) 2018.04.20
인터페이스  (0) 2018.04.20
상속  (0) 2018.04.17
복합객체  (0) 2018.04.17
메시지  (0) 2018.04.16