관리 메뉴

드럼치는 프로그래머

[JAVA] 추상클래스의 개념 본문

★─Programing/☆─JAVA

[JAVA] 추상클래스의 개념

드럼치는한동이 2007. 10. 29. 11:22


5.1.1 추상클래스의 개념


Abstract클래스는 빈 깡통 클래스입니다. abstract클래스는 구현이 덜 되었거나 또는 아직은 미완성 클래스이기 때문에 우리는 이 클래스를 추상 클래스라 부릅니다. 어디가 미완성일까요? 미완성 메서드를 포함하고 있기 때문에 클래스자체가 미완성이 되는 것입니다. 미완성 메서드는 어디가 미완성일까요? 메서드의 몸체가 없습니다. 몸체 없는 메서드, 이를 우리는 추상 메서드라 부릅니다. 그리고 이 추상 메서드를 단 하나라도 포함하고 있는 클래스를 추상 클래스라고 합니다.

 

 

5.1.2 추상클래스와 추상메서드

 추상클래스는 미완성 클래스이기 때문에 약점이 있습니다. 완전한 클래스가 아니기 때문에 절대 객체를 생성하지 못합니다. 당연한 것 아니겠습니까? 완성되지 않은 클래스이니 객체를 만들 수 없다는 것은 이치에 합당합니다. 이 미완성 클래스를 어디에 사용할까요? 사용방법은 다음과 같습니다.(이해하기 편하게 추상클래스를 추상아버지클래스, 이를 상속 받는 클래스를 아들클래스라고 하겠습니다. )

 

n        추상아버지 클래스는 추상 메서드를 가지고 있습니다.

n        아들 클래스는 추상 아버지클래스로부터 상속 받습니다.

n        아들은 추상 아버지 클래스의 몸체 없는 메서드를 모두 메서드 재정의와 같이 다시 만듭니다. 이것을 우리는 구현한다고 말합니다. 몸체를 달아 주는 것입니다.

n        아들 클래스는 완성된 클래스이기 때문에 객체를 생성할 수 있습니다.

 

 다음은 추상 메서드를 만드는 방법을 보여 주고 있는 예입니다.

추상 메서드를 만드는 방법

abstract class 클래스이름 {

abstract 메소드선언;        // 메소드의 몸체는 없음

abstract 메소드선언;        // 메소드의 몸체는 없음

}

 

)

 

public abstract class AbstractTest {

   public abstract void abstractMethod();

}

 

메서드에 몸체가 붙지 않는다면 여러분은 반드시 abstract키워드를 붙여야 합니다. 그리고 이 abstract메서드를 하나라도 포함하고 있다면 클래스명 앞에 abstract를 붙여야 합니다. 안 붙이면 언제나 그런 것처럼 친절하게 에러를 발생 시킵니다. 아래의 에러는 추상클래스내에 추상 메서드에 abstract를 붙이지 않았을 때 발생하는 에러입니다.

 

C:\examples\5. Class for Polymorphism Java>javac AbstractTest.java

AbstractTest.java:2: missing method body, or declare abstract

        public void abstractMethod();

                    ^

1 error

 

아주 간단하죠. 추상 클래스는 그 자체로는 객체를 생성할 수 없다는 것을 한번 더 밝혀 두며 실제 이용하는 가장 간단한 예를 보도록 하겠습니다.

 

NewCan.java(추상 메서드를 만드는 방법)

public class NewCan extends EmptyCan{

             public void sound(){

                           System.out.println("EmptyCan:빈깡통은 소리가 요란하다");

             }

             public void who(){

                           System.out.println("EmptyCan:나는 빈깡통입니다.");

             }

             public void sayHello(){

                           System.out.println("NewCan:추상클래스 테스트입니다.");

             }

             public static void main(String args[]) {

                           NewCan ecm = new NewCan();

                           ecm.who();

                           ecm.sound();

                           ecm.sayHello();

             }

}

Empty.java(추상클래스)

public abstract class EmptyCan{  

   public abstract void sound();//몸체없음

   public abstract void who();//몸체 없음  

}

C:\examples\5. Class for Polymorphism Java>javac NewCan.java

 

C:\examples\5. Class for Polymorphism Java>java NewCan

EmptyCan:나는 빈깡통입니다.

EmptyCan:빈깡통은 소리가 요란하다

NewCan:추상클래스 테스트입니다.

 

추상클래스는 객체가 가지는 특성들을 추상화시켜 놓았을 뿐, 아직 구체화 시키지 못한 클래스이므로, 이 추상클래스를 상속하는 하위클래스에서 좀 더 구체화 시키도록 하는 방법을 사용합니다. 주의 할 것은 추상 메서드를 하나도 빼지 말고 전부 구현 해야 객체를 생성할 수 있습니다. 아들이 상속을 받아서 추상 메서드를 하나라도 남겨 두었다면 아들도 추상클래스가 됩니다. 부전자전이죠. 다음은 상속을 했지만 추상 메서드를 전부 구현 하지 않았다면 abstract클래스가 되는 것을 증명하는 예제입니다.

 

CompleteCan.java(추상 메서드를 만드는 방법)

public class CompleteCan extends IncompleteCan{

             public void who(){

                           System.out.println("EmptyCan:나는 빈깡통입니다.");

             }

             public void sayHello(){

                           System.out.println("NewCan:추상클래스 테스트입니다.");

             }

             public static void main(String args[]) {

                           CompleteCan cc = new CompleteCan();

                           cc.who();

                           cc.sound();

                           cc.sayHello();

             }

}

Incomplete.java(추상클래스)

public abstract class IncompleteCan extends EmptyCan{

             public void sound(){

                           System.out.println("EmptyCan:빈깡통은 소리가 요란하다");    

             }

}

Empty.java(추상클래스)

public abstract class EmptyCan{  

   public abstract void sound();//몸체없음

   public abstract void who();//몸체 없음  

}

C:\examples\5. Class for Polymorphism Java>javac EmptyCan.java

C:\examples\5. Class for Polymorphism Java>javac IncompleteCan.java

C:\examples\5. Class for Polymorphism Java>javac CompleteCan.java

C:\examples\5. Class for Polymorphism Java>java CompleteCan

EmptyCan:나는 빈깡통입니다.

EmptyCan:빈깡통은 소리가 요란하다

NewCan:추상클래스 테스트입니다.

 

추상메소드는 추상클래스와 마찬가지로 아직 구현이 이루어지지 않고 단지 그 메서드의 이름만 가지고 있다는 뜻입니다. 그래서 몸체가 없다고 말하고 있는 것입니다. 이것을 역으로 말한다면 추상메서드가 되려면 몸체가 없어야 한다라는 명제를 얻을 수 있습니다. 보통 우리가 전문적인 용어로 이야기 할 때 추상메서드는 메서드의 프로토타입만 가지고 있다라고 이야기 합니다. 

 

 

5.1.3 클래스의 구조를 디자인하기 위한 추상 클래스

 추상클래스는 클래스의 구조를 잡기 위한 방법으로 사용됩니다. 하나의 클래스를 만든다고 가정한다면 하나의 클래스에 모든 것을 전부 넣을 수는 없습니다. 이러한 방법은 별로 좋지 않은 방법이죠. 클래스가 크다고 가정한다면 작업별로 클래스를 쪼개게 됩니다. 작업을 분할 하는 것은 수평적인 개념에서 비슷한 작업끼리 묶는 것입니다. 유유상종(類類相從)이라는 말이 적당할 것 같군요. 비슷한 작업끼리 묶어서 작업별 클래스를 만드는 것입니다.

 

저 또한 초보시절의 자바 프로그램은 비슷한 작업을 묶는 것으로 시작했습니다. 하지만 수평적으로 묶는 것 조차도 작업의 설계와 분석을 해야만 이루어지는 아주 어려운 일입니다. 이 단계를 거치고 나면 작업을 레벨단위로 묶는 것을 생각하게 됩니다. 거의 1년 이상 걸리더군요. 제가 머리가 나빠서 그런지도 모르겠지만 개인적으로는 상당히 어려운 일이었습니다. 레벨 단위의 작업으로 발전하기까지는 상당히 많은 시간과 생각이 필요한 것 같습니다. 작업을 단계별로 만들어 주는 역할을 하는 것이 바로 추상 클래스의 역할입니다.

레벨 단위의 구조를 살펴 보도록 하죠.

위의 그림은 도형을 그리기 위한 클래스를 디자인 하고 있습니다. 모든 클래스에서 공통되는 작업을 상위레벨에 놓고 그 클래스를 상속 받아 각각의 다른 클래스로 분류되어지고 있습니다. 상위레벨에 존재하는 작업은 구현할 필요성이 없다고 생각하여 abstract으로 만듭니다. 즉, 하위레벨에서 구현하겠다는 것입니다. 이렇게 하였을 때의 코드를 직접 만들어 보겠습니다. 물론 Shape클래스는 abstract으로 만들어질 것이며 그 하위의 Circle, Triangle, Rectangle은 모두 Shape의 abstract메서드를 구현 할 것입니다. 구현은 대충 아래와 같이 되어 질 것입니다.

 

FigureTest.java(abstract의 레벨기법을 테스트하기 위한 예제)

abstract class Shape {

             public abstract void draw();

             public abstract void delete();

}

class Circle extends Shape {

             public void draw(){

                           System.out.println("원을 그립니다");           

             }

             public void delete(){

                           System.out.println("원모양을 지웁니다");     

             }

}

class Triangle extends Shape {

             public void draw(){

                           System.out.println("삼각형을 하나, 둘, 셋, 그립니다.");          

             }

             public void delete(){

                           System.out.println("삼각형을 지웁니다");     

             }

}

class Rectangle extends Shape {

             public void draw(){

                           System.out.println("사각형을 원, 투, 쓰리, 포 그립니다.");     

             }

             public void delete(){

                           System.out.println("사각형을 지웁니다");     

             }

}

//abstract을 테스트하기 위한 클래스

public class FigureTest{

             public static void main(String[] args){

                           Circle c = new Circle();

                           Triangle t = new Triangle();

                           Rectangle r = new Rectangle();

                           c.draw();

                           t.draw();

                           r.draw();

                           c.delete();

                           t.delete();

                           r.delete();

             }

}

C:\examples\5. Class for Polymorphism Java>javac FigureTest.java

C:\examples\5. Class for Polymorphism Java>java FigureTest

원을 그립니다

삼각형을 하나, 둘, 셋, 그립니다.

사각형을 원, 투, 쓰리, 포 그립니다.

원모양을 지웁니다

삼각형을 지웁니다

사각형을 지웁니다

 

상속과 abstract을 설명하기 위해서 어디서나 흔히 볼 수 있는 예제입니다. 이 간단한 예제가 무엇을 의미하는지 제대로 안다면 자바의 강력한 힘을 발휘할 수 있습니다. 클래스의 수평적인 작업 분할과 수직적인 작업 분할을 동시에 이용한다면 여러분은 아주 효율적인 코드를 작성할 수 있습니다. 재사용성 100%와 유지, 보수, 관리 능력까지 갖춘 잘 설계된 프로그램을 하실 수 있을 것입니다.

 

 

5.1.4 결론

추상클래스에 대하여 정리 해 보죠.

 

n         추상 메서드는 몸체 없는 프로토타입만을 가진 메서드입니다.

n         추상 메서드는 반드시 메서드이름 앞에 abstract 키워드를 명시해야 합니다.

n         추상 메서드를 단 하나라도 포함하고 있으면 이를 추상 클래스라고 합니다.

n         추상 클래스는 클래스이름 앞에 abstract를 명시해야 합니다.

n         상속을 이용하여 추상 메서드를 모두 구현한 뒤, 객체를 생성할 수 있습니다.

 

일반적인 특징은 이러하지만 추상클래스의 뒷면에 존재하는 느낌은 수직적인 작업의 분할이라는 아주 무서운 개념이 숨어 있습니다. 프로그램을 하면서 어떻게 계층적으로 프로그램을 할지를 결정하지말고 펜을 들고 작업을 분석하는 것이 옳을 것입니다. 그리고 작업 분석이 끝났다면 수직과 수평의 개념을 적용 시켜서 어느 정도 설계를 하는 것이 옳을 것입니다. 하지만, 기본적인 배경 없이는 아무것도 할 수 없으니 지금은 느낌을 얻으시기 바랍니다.

 

여러분이 클래스를 만들고 시간이 지나서 다시 여러분이 만든 클래스를 볼 기회 있을 것입니다. 절대 같은 디자인의 클래스는 만들 수 없습니다. 물론, 클래스를 만드는 기법은 비슷하지만 같은 디자인으로는 프로그램을 하려고 해도 잘 되지 않습니다. 약간의 시간이 지난 후, 과거와 현재를 비교해 보면 여러분 스스로 진화했다는 말을 사용해도 될 만큼 아주 많은 발전을 이룬 것을 볼 날이 있을 것입니다.

Comments