추상화(Abstract)
‘추상적이다.’라는 말을 들으면 나는 애매모호하고 두루뭉실한 느낌이 들었는데, 그래서 그런지 처음 추상화를 들었을 때도 그런 기분이었다.
객체 지향 관점에서의 추상화는 클래스를 정의할 때, 불필요한 부분들을 생략하고 객체의 속성 중 중요한 것에만 중점을 두어 개략화 하는 것, 즉 클래스들의 중요하고 공통된 성질들을 추출하여 슈퍼 클래스를 선정하는 개념이다.
뭐 사실 이론적으로 설명하면 처음에는 뭐라는지 하나도 모르겠다.(본인이 그랬음) 내가 이해한 내용을 요약해서 이야기하자면 다음과 같다.
우선 앞서 포스팅한 메서드와 클래스의 개념을 떠올리자면 클래스안에 메서드가 존재했는데, 추상 클래스(Abstract Class) 안에 추상 메서드(Abstract method)가 존재한다.
검색해보면 Dog, Cat, Animal 이런 식으로 정리해놓은 코드들이 많은데, 이해는 되는데 뭐랄까 사용해보면 잘 모르겠어서 포스팅한다고 직접 코드를 짜봤다.
기본적으로 선언 자체는 Class나 method 앞에 abstract 제어자를 붙이면 완성이다.
abstract class AbstractClass { // abstractClass를 추상 클래스로 선언
void printIsAbs(int n) { // printIsAbs 메서드 선언
System.out.println(n);
}
abstract int isAbs(int n); // isAbs 메서드를 추상 메서드로 선언
}
근데 생각해보면 우리가 메서드를 사용하려면, 분명 그 기능이 안에 있어야 하는데,
isAbs 메서드는 도대체 무슨 메서드인지 모른다. (해도 이름으로만 감을 잡아야하는 상황이다.)
이 개념은 상속받는 클래스가 나타나야 해결할 수 있다.
public class ExtendClass extends AbstractClass {
int isAbs(int n) {
return Math.abs(n);
}
public static void main(String[] args) {
ExtendClass extendClass = new ExtendClass();
extendClass.printIsAbs(-5);
}
} // 출력: 5
갑자기 뭐 이리 바리바리 적어놨나 할 수 있는데 하나씩 보면 쉽다.
public class ExtendClass extends AbstractClass
AbstarctClass를 상속받는(extends) ExtendClass라는 클래스를 선언
int isAbs(int n) {
return Math.abs(n);
}
ExtendClass 클래스 안에 INT형으로 리턴하는, 정수 n을 인수로 받는 isAbs 메서드가 있다.
기능은 n의 절대값 처리
ExtendClass extendClass = new ExtendClass();
ExtendClass 클래스 객체화(isAbs 메서드 호출을 위한 것)
extendClass.printIsAbs(-5);
AbstractClass 클래스 안 printIsAbs메서드를 호출 후, 인자 -5를 넣고 사용
위 코드처럼 사용할 수 있는데, 여기서 아마 두가지 의문점이 생길거다.(아마도)
- ExtendClass 클래스에는 printIsAbs 메서드가 없는데 어떻게 사용했는지?
- AbstractClass 클래스에는 isAbs 메서드가 미완성 상태인데 어떻게 작동했는지?
간단하게 하나씩 답변하자면
첫 번째로, ExtendClass는 AbstractClass를 상속(extends)받았기 때문에 사용 가능하다.
부모가 자식한테 재산을 물려주면 자식이 재산을 사용하듯 말이다.
두 번째로는 부모가 빚까지 물려주면 자식은 그걸 반드시 갚아야 한다… 이런 비유가 맞나 모르겠다...
개념적으로 설명하자면 추상 클래스(AbstractClass)를 상속받는 클래스(ExtendClass)는 갖고 있는 추상 메서드(isAbs)를 반드시 구현해줘야 한다.
이 과정을 오버라이딩(Overriding)이라고 하는데,
말 그대로 추상 클래스의 추상 메서드를 상속받는 클래스의 같은 명의 메서드로 덮어 쓰는거다.
말하자면 추상 클래스는 붕어빵 틀과 반죽이 준비되어있는데 재료를 넣으라고만 써있는 것이고,
팥, 슈크림, 김치(?) 중 뭘 넣을지 상속받는 메서드에서 결정하는 것.
그림으로 보자면 이런 느낌이다.
이 정도가 내가 알고 있는 추상화에 대한 기본적인 느낌이다.
위에서 설명한 내용을 포함하여 특징들을 정리하자면 다음과 같다.
- 추상 클래스는 클래스 앞에 abstract 키워드를 이용하여 정의한다.
- 추상 클래스는 미구현의 메서드를 포함할 수 있다.
미구현된 메서드는 추상 메서드라 하며 추상 클래스와 비슷하게 리턴 타입 앞에 abstract 키워드를 붙여야 한다. - 인터페이스와 다른 특징 중 하나인데, 추상 클래스는 구현된 메서드도 포함할 수 있다는 것
(인터페이스는 구현된 메서드를 포함할 수 없다.) - 추상 클래스를 상속받는 클래스는 추상 클래스가 갖고 있는 추상 메서드를 구현해야 한다.
(반드시 해야하며, 안 할 시 작동을 안한다. 이 과정을 오버라이딩(Overriding)이라 한다.) - 추상 클래스는 객체 생성 불가(인스턴스화 시킬 수 없음)
뭐 사용 이유는 다른 블로그에 많이들 정리되어있는데,
아까 붕어빵처럼 얘기하자면 넣고 싶은 재료가 많아졌다고 붕어빵 틀을 늘릴 순 없으니 분리시키는 것…
작업자들이 많아짐 → 공통적으로 작성해야 하는 내용이 생김 → 출력은 똑같은데 이름과 설계가 다름
→ 유지보수, 관리 문제 발생 → Abstract Class가 필요한 이유
라는 절차를 거친다고 보면 된다.
유지보수, 통일성, 코스트 절약, 구현에만 집중 등 도움이 된다고 한다만
사실 인터페이스를 더 사용한다고 보면 된다.
그래서 다음 글은 인터페이스 (다음 글은 이런 형식으로 안 작성할 것 같다…)
참고 블로그 : [Java] Abstract Class(추상 클래스)
Notion Link : https://www.notion.so/Abstract-eeee9f2184ab4af891c90b144066d715