abstract, Design Pattern

muz·2021년 4월 17일
0

Java

목록 보기
13/21
post-thumbnail

⚾ abstract?

abstract은 상속을 강제하는 규제와 같다. 즉 abstract 클래스, 메소드를 사용하기 위해서는 반드시 상속해서 사용하는 것이 abstract이다.

추상 메소드

메소드의 시그니처만이 정의된 빈 메소드를 의미한다. 다음 코드를 작성해보자.

public class abstractCode {
    public static void main(String[] args) {
        A obj = new A();
    }
}

abstract class A {
    public abstract int b();
    // 내용이 있는 메소드는 abstract 키워드를 가질 수 없음 
    // 추상 클래스 내에는 추상 메소드가 아닌 메소드가 존재할 수 있음
    public void d() {
        System.out.println("world");
    }
}

컴파일을 하면 아래 사진과 같은 Error가 뜨는 것을 확인할 수 있다.

메소드b의 선언에 abstract 키워드가 등장하고 있다. 메소드b는 메소드의 시그니처만 정의되어 있고, 구체적인 구현은 하위 클래스에서 오버라이딩해야 한다는 의미이다. 이렇게 내용이 비어있는 메소드추상 메소드라고 부른다.
추상 메소드를 하나라도 포함하고 있는 클래스는 추상 클래스가 되고, 클래스 앞에 abstract가 붙는다.

때문에 메소드c는 오류가 발생할 수밖에 없다. 본체가 있는데 추상 메소드를 의미하는 abstract를 붙여주었기 때문이다.

public abstract int c() {
        System.out.println("Hello");
    }

추상 클래스라고해서 추상 메소드만 존재할 수 있는 것은 아니다. 추상 클래스에도 메소드가 존재할 수 있다.

 public void d() {
        System.out.println("world");
    }

그러나 추상 클래스 A를 인스턴스화( A obj = new A(); )하면 오류가 발생한다. 추상 클래스는 구체적인 메소드의 내용이 존재하지 않기 때문에 인스턴스화시켜서 사용할 수 없기 때문이다.

어떻게 해야 클래스A를 사용할 수 있을까?

추상 클래스의 상속

클래스A를 사용하는 방법은 다음과 같다.

  1. 클래스 A를 상속한 하위 클래스 만들기
  2. 추상 메소드를 오버라이드해서 내용있는 메소드로 만들기

이 방법을 이용하여 "클래스A 이용하기"를 출력해보자.

public class abstractCode {
    public static void main(String[] args) {
        B obj = new B();
        System.out.println(obj.b());
    }
}

// 추상 클래스A 
abstract class A {
    public abstract String b();
    
    public void d() {
        System.out.println("world");
    }
}

// 클래스A를 상속한 하위 클래스 만들기
class B extends A {
    public String b() {
        String syn = "클래스A 사용하기";
        return syn;
    }
}

클래스B는 클래스A를 상속했다. 클래스A의 추상 메소드인 메소드b를 오버라이딩하고 있다.

추상 클래스를 사용하는 이유?

추상 클래스는 상속을 강제하기 위함이다. 부모 클래스에는 메소드의 시그니처만 정의해놓고, 그 메소드의 실제 동작 방법은 이 메소드를 상속 받은 하위 클래스의 책임으로 넘기고 있다.

추상 클래스를 계산기 예제에 적용해보자.

// 추상 클래스 ab_cal
abstract class ab_cal{
    int left, right;

    public void setOprands(int left, int right){
        this.left = left;
        this.right = right;
    } 
    public abstract void sum(); // 추상 메소드sum 선언
    public abstract void avg(); // 추상 메소드avg 선언

    public void run(){
        sum();
        avg();
    }
}

// 추상 클래스 ab_cal을 상속받는 클래스CalculatorDP
class CalculatorDP extends ab_cal { 
    // 추상 클래스ab_cal의 추상 메소드sum, avg를 오버라이딩 함
    public void sum(){
        System.out.println("+++++ sum :"+(this.left+this.right));
    }
    public void avg(){
        System.out.println("+++++ avg :"+(this.left+this.right)/2);
    }
}

// 추상 클래스 ab_cal을 상속받는 클래스CalculatorDM 
class CalculatorDM extends ab_cal { 
    // 추상 클래스ab_cal의 추상 메소드sum, avg를 오버라이딩 함
    public void sum(){ 
        System.out.println("----- sum :"+(this.left+this.right));
    }
    public void avg(){
        System.out.println("----- avg :"+(this.left+this.right)/2);
    }
} 
public class abstractCalculator {
    public static void main(String[] args) { 
        CalculatorDP c1 = new CalculatorDP();
        c1.setOprands(10, 20);
        c1.run();
         
        CalculatorDM c2 = new CalculatorDM();
        c2.setOprands(10, 20);
        c2.run();
    }
}


위의 코드는 sum을 실행하고, avg를 실행하는 절차를 메소드run을 통해 한 번에 실행되게끔 한 것이다. 경우에 따라 sum, avg를 화면에 다른 모습으로 출력해야할 때, 상황에 따라 동작 방법이 달라지는 메소드sum, avg는 추상 메소드로 만들어서 하위 클래스에서 구현하도록 하고 모든 클래스에서 공통으로 사용되는 setOprands, run은 상위 클래스에 두고 코드의 중복, 유지보수의 편의성을 얻을 수 있다.

이러한 개발 방법을 template method pattern이라고도 하는데, 템플릿은 모양을 결정하지만 펜의 종류나 색상에 따라 완성작이 달라진다. 공통분모인 메소드run은 sum, avg가 어떻게 동작하는지 알 수 없지만 sum이 실행되고 avg를 실행시킨다. 실행결과를 어떤 기호로 시작할지는 하위 클래스에서 결정하고 있다.

🏀 디자인 패턴

프로그래밍에도 반복되는 패턴이 있다. 이러한 패턴들을 모아 정리한 것이 디자인 패턴(design pattern)이라 한다. 디자인 패턴의 장점은 무엇일까?

🎨 디자인 패턴의 장점?
1. 좋은 설계를 비교적 단기간에 학습할 수 있음
2. 소통에 도움이 됨


Reference
1. abstract

profile
Life is what i make up it 💨

0개의 댓글