추상화

김하영·2020년 12월 21일
0
post-custom-banner

2020-12-21 Topic!

  • 프로그램 세계에서의 추상화 의 개념 (정의, 효과, 장/단점 등)
  • interface 의 개념
  • 추상화를 적용한 프로그래밍 사례 3가지

추상화

  1. 정의
  • 복잡한 자료, 모듈, 시스템 등으로부터 핵심적인 개념 또는 기능을 간추려 내는 것
  • 어떤 작업을 수행할 때 그 이면에 존재하는 복잡한 것들을 간단한 것처럼 보이게 만들어주는 것

현실세계에서 '추상화'란?

포토샵을 사용하여 컬러 사진을 흑백 사진으로 변경한다고 생각해보자.
포토샵은 이미지 프로세싱이라는 복잡한 연산을 수행하는 프로그램이지만,
우리는 포토샵이 제공하는 여러가지 기능들을 사용하여 사진 보정이라는 행위에만 집중할 수 있다.

실제로 컬러 사진을 흑백 사진으로 변경할 때는 행렬로 이루어진 사진의 픽셀 데이터를 순회하며
RGB 값의 평균을 내거나하는 등의 과정을 수행해야한다.

하지만 그런 복잡하고 귀찮은 과정이 추상화되어있기 때문에 사용자는
그저 포토샵이 외부로 노출해준 기능인 Image > Adjustments > Desaturate을 사용하면 되는 것이다.

객체 지향적 관점에서 '추상화'란?

  • 클래스를 정의하는 것
  • 불필요한 부분을 생략하고 객체의 속성 중 가장 중요한 것에만 중점을 두어 개략화하는 것

즉, 모델화하는 것으로 데이터의 공통된 성질을 추출하여 슈퍼 클래스를 선정하는 개념이다.

  1. 효과 / 장점
  • 모델링
  • 코드의 재사용성
  • 코드의 가독성
  • 일관된 방향성
  • 생산성의 증가
  • 에러 감소
  • 유지 보수시, 시간 단축

모델링을 통해 코드를 추상화하면 코드의 재사용성을 높일 수 있고 코드의 가독성을 높여
코드를 이해하기 훨씬 더 쉽게 만들어 주기도 한다. 그리고 추상화된 코드는 자연스럽게 일관성을 가지게 된다.

따라서, 생산성이 높아지고 에러가 감소되는 영향을 미치게 된다.

프로그래머가 기능 개발에 투자하는 시간보다 유지 보수, 버그 해결에 많은 시간을 쓴다는 것을 감안하면,
추상화의 중요성이 크다는 것을 인식할 수 있다.

우리가 많은 것을 기억해야 할 때 모든 것을 외운다기보다는 패턴이나 맥락을 외우면
기억해야 할 양이 줄면서 기억에 남는 것을 생각하면 이해할 수 있다.

  1. 단점
  • 내부파악 및 수정이 어렵다.

간단하게 생각해보면 추상화를 했을 때, 내부를 몰라도 그냥 사용할 수 있다.

반대로 생각하면 추상화된 것은 조금 다르게 수정해서 사용하고 싶더라도 내부의 어떤 것이 있을지 또는 얼마나 복잡한지 몰라서 쉽지 않다.

따라서 작게작게 추상화시켜서 조금 다른 기능을 만들기 위해서 블럭을 조립하듯 만들어진 것을 잘 정리된 추상화라고 할 수 있다.

  • 성능 저하

자바의 경우에는 바이트 코드와 JVM(Java Virtual Machine)이라는 개념을 사용하여 한번만 코드를 작성해도 모든 OS에서 동작하는 프로그램을 작성할 수 있다는 점이 굉장한 강점이었다.

OS나 CPU에 종속되어있던 기존의 프로그래밍 언어들에 비해 추상화 수준이 높아진 것이다.
그러나 처음 자바가 나왔을 당시에는 C에 비해서 너무 느려서 못 써먹을 물건이라고 상당히 많이 까였다.

또한 가비지 컬렉터도 개발자가 일일히 메모리를 할당하고 해제하지 않아도 되는 편리함을 제공하지만 GC가 객체의 메모리 해제 시점을 매번 추적하고 있어야하는 성능 문제나, 개발자가 객체가 메모리에서 해제되는 시점을 정확히 알기 어렵다던가, 참조 횟수 계산 방식을 사용할 때 순환 참조 객체를 해제하지 못하는 등 문제들이 여전히 존재하기 때문에 늘 완벽하게 동작하지는 않는다.

하지만 그렇다고 자바나 가비지 컬렉터나 자바를 사용할 수 있는 환경에서 굳이 C를 사용하고 수동으로 메모리를 관리하고 싶어하는 사람이 많지는 않을 것이다.

애초에 이런 높은 수준의 추상화를 제공하는 기술이 가지는 성능 상의 단점을 머신이 어느 정도 커버할 수 있기 때문에 사람들이 많이 사용하는 것이기도 하다.

참고 : https://evan-moon.github.io/2019/12/15/about-functional-thinking/

interface

  1. 개념

    어떤 객체에 대한 명제로 이 객체가 어떤 메서드들을 제공하고 어떤 역할을 하는지에 대한 일종의 설명서

자식 클래스가 여러 부모 클래스를 상속받을 수 있다면, 다양한 동작을 수행할 수 있다는 장점을 가진다.

하지만 클래스를 이용하여 다중 상속을 할 경우 메소드 출처의 모호성 등 여러 가지 문제가 발생할 수 있어 자바에서는 클래스를 통한 다중 상속은 지원하지 않는다.

즉, 다중 상속의 이점을 버릴 수는 없기에 자바에서는 인터페이스라는 것을 통해 다중 상속을 지원하고 있다.

인터페이스(interface)란 다른 클래스를 작성할 때 기본이 되는 틀을 제공하면서, 다른 클래스 사이의 중간 매개 역할까지 담당하는 일종의 추상 클래스를 의미한다.

자바에서 추상 클래스는 추상 메소드뿐만 아니라 생성자, 필드, 일반 메소드도 포함할 수 있다.
하지만 인터페이스는 오로지 추상 메소드와 상수만을 포함할 수 있다.

  1. 선언과 구현
	//1번
public interface Calc {
	//2번	
	double PI = 3.14; //나중에 상수가됨
	int ERROR = -9999999;
	//3번
	int add(int num1, int num2);
	int substract(int num1, int num2);
	int times(int num1, int num2);
	int divide(int num1, int num2);
}

1번 : 계산을 기능을 하는 객체에 인터페이스를 작성하기 위해 Calc클래스를 만들고 클래스 선언부(public class Clac)에 class를 지우고 interface를 적으면 인터페이스로 선언된다.

또한 클래스를 생성할 때 클래스로 생성하지 않고 바로 인터페이스를 생성하는 방법도 있다.

2번 : 변수 PI와 ERROR은 실제 변수가 아닌 상수로 컴파일과정에서 public static final이 다 붙어서 상수화된다.

3번 : 계산 기능을 하는 add(), substract(), times(), divde() 메서드를 만든다. abstract 키워드가 생략됬지만 이들은 구현부가 없는 추상메서드 이다. 이 메서드들도 컴파일 과정에서 추상 메서드로 변환한다.

메서드를 함수의 이름, 매개변수 반환값을 선언할 수 있다는 것은 결국 이 메서드가 어떤 기능을 대략적으로 보여주는 기능을 한다.

인터페이스는 이렇게 객체의 기능을 간략하게 설명하는 기능을 하고 하위 클래스에서 어떻게 구현되야 하는지를 안내한다.

  1. abstract class와 interface

공통점

  • 선언만 있고 구현 내용이 없는 클래스이다.

자기 자신이 new를 해서 객체를 생성할 수 없으며
추상클래스를 extends 받거나, interface를 implements 한 자식만이 객체를 생성할 수 있다.

  • 상속받은 자식이 구현을 반드시 하도록 해야할 때 사용한다.

타입이 지정되있기 때문에 선언된 타입과 자식의 타입이 같아야만 한다.

차이점

  • 추상클래스는 말그대로 클래스이고, interface는 구현하기 전에 메소드에 대해 명세된 구현체이다.

그래서 상속을 받음에도 불구하고 클래스에선 상속이라고 쓰지만 interface는 implemets(구현) 이라고 쓴다.

추상클래스의 정의는 abstract 메소드가 하나라도 존재하는 클래스를 일컫는다.
때문에 일부는 구현된 메소드도 있고, abstract라고 붙어있는 메소드는 구현이 안되어있다.

추상클래스를 상속받는 클래스는 반드시 추상메소드를 구현해야한다.
그래서 필수적으로 구현해야할 메소드가 있을 때 추상클래스를 쓰게된다.

인터페이스는 구현체 없이, 메소드에 대한 명세만 되어있다.
인터페이스를 상속받는 클래스에서는 반드시 인터페이스에 있는 메소드를 다 구현해야한다.

  • 추상클래스는 단일상속이지만, interface는 다중상속이 가능하다.

자바는 단일상속을 지원하기 때문에 추상클래스는 단일상속이지만,
interface를 사용하게 되면 implements를 구현하는 부분에서 extends 또한 사용할 수 있다.
즉, 다중상속이 가능해진다.

'이러이러한 메소드를 쓸 것이다.' 인터페이스에 선언을 해놓고, 가져다가 반드시 선언된 그대로 모두 구현하면 되는게 인터페이스이고,

이러이러한 메소드가 있지만 가져다 쓰거나 오버라이드 하거나, abstract가 붙은 메소드는 반드시 구현하면 되는게 abstract class이다.

  1. 용도

인터페이스는 다형성에 대한 개념(Polymorphism)으로 추상화를 구현하였고
추상 클래스는 상속에 대한 개념으로 추상화(Overriding)를 구현하였다.

즉, 인터페이스는 무조건 implemets 되어야 하는 상수,추상메소드를 추상화한 구현체로
자식 클래스에서 다양한 형태로 재정의할 때 사용한다.
(예 - 동물 인터페이스를 동물 클래스인 곰, 병아리에 implemets 한다.)

추상클래스는 부모 추상 클래스의 기능을 유전받으면 그에 대한 기능을 더 추가하거나 수정한다.
(예 - 곰 추상 클래스를 반달가슴곰 클래스에 extends 한다.)

추상화를 적용한 프로그래밍 사례 3가지

  1. 추상 클래스를 이용한 예제
// 추상 클래스
public abstract class EmptyCan { 
    public abstract void printContent(); //추상 메서드  
    public abstract void printName(); //추상 메서드
}

public class BeerCan extends EmptyCan{ 
    public void printContent() { //EmptyCan의 printContent() 구현 
        System.out.println("흑맥주");
    }
    public void printName() { //EmptyCan의 printName() 구현 
        System.out.println("맥주캔입니다.");
    }
    public void sayHello() { //새로운 멤버 메서드 추가
        System.out.println("안녕하세요 맥주캔입니다.");
    }
    public static void main(String args[]) {
        BeerCan b = new BeerCan();
        b.printContent(); 
        b.printName(); 
        b.sayHello();
    } 
} 
  1. interface를 이용한 예제
interface hello {
  public void sayHello();
}

interface bye {
  public void sayBye();
}

class TalkinRobot implements hello, bye {
  public void sayHello(){
    System.out.println("안녕!");
  }

  public void sayBye(){
    System.out.println("잘가!");
  }
}
  1. interface를 활용한 골격 구현 추상 클래스
public abstract class AbstractMapEntry<K,V> implements Map.Entry<K,V> {
    @Override 
    public V setValue(V value) {
        throw new UnsupportedOperationException();
    }
    
    @Override 
    public boolean equals(Object o) {
        if (o == this) {
            return true;
        }
        if (!(o instanceof Map.Entry)) {
            return false;
        }
        Map.Entry<?,?> e = (Map.Entry) o;
        return Objects.equals(e.getKey(),   getKey()) && Objects.equals(e.getValue(), getValue());
    }

    @Override 
    public int hashCode() {
        return Objects.hashCode(getKey()) ^ Objects.hashCode(getValue());
    }

    @Override 
    public String toString() {
        return getKey() + "=" + getValue();
    }
}

참고 : https://happy-playboy.tistory.com/entry/Item-20-%EC%B6%94%EC%83%81-%ED%81%B4%EB%9E%98%EC%8A%A4%EB%B3%B4%EB%8B%A4%EB%8A%94-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4%EB%A5%BC-%EC%9A%B0%EC%84%A0%ED%95%98%EB%9D%BC

  • 질문
  1. 추상화라는 개념이 너무나 추상적(?)이라서 사람마다 이해하는 추상화가 다 다를 거라고 생각이 됩니다. 메트가 생각하는 추상화라는 개념이 궁금합니다~

  2. 제가 이해한 추상메소드와 인터페이스의 용도가 정확한가요~?


인터페이스는 다형성에 대한 개념(Polymorphism)으로 추상화를 구현하였고
추상 클래스는 상속에 대한 개념으로 추상화(Overriding)를 구현하였다.

즉, 인터페이스는 무조건 implemets 되어야 하는 상수,추상메소드를 추상화한 구현체로
자식 클래스에서 다양한 형태로 재정의할 때 사용한다. 
(예 - 동물 인터페이스를 동물 클래스인 곰, 병아리에 implemets 한다.)

추상클래스는 부모 추상 클래스의 기능을 유전받으면 그에 대한 기능을 더 추가하거나 수정한다.
(예 - 곰 추상 클래스를 반달가슴곰 클래스에 extends 한다.)
  1. 실제로 추상클래스와 인터페이스를 활용하여 골격 구현 관련 추상 클래스를 실무에서 많이 쓰나요?
public abstract class AbstractMapEntry<K,V> implements Map.Entry<K,V> {
    @Override 
    public V setValue(V value) {
        throw new UnsupportedOperationException();
    }
    
    @Override 
    public boolean equals(Object o) {
        if (o == this) {
            return true;
        }
        if (!(o instanceof Map.Entry)) {
            return false;
        }
        Map.Entry<?,?> e = (Map.Entry) o;
        return Objects.equals(e.getKey(),   getKey()) && Objects.equals(e.getValue(), getValue());
    }

    @Override 
    public int hashCode() {
        return Objects.hashCode(getKey()) ^ Objects.hashCode(getValue());
    }

    @Override 
    public String toString() {
        return getKey() + "=" + getValue();
    }
}
  1. 제가 생각하는 추상화
  • 관심사에 맞춘 단순화 라고 생각합니다. 프로그램의 목적은 원하는 결과를 얻어내기 위함인데, 그 목적을 달성하기 위해 굉장히 복잡한 과정이 필요할 수 있습니다.
    하지만 이미 검증된 과정에 대해서 모든 프로그래머가 매번 개발을 해야 한다면 생산성부터 시작해서 품질 등 많은 문제점이 발생할 수 있습니다.
    즉, 추상화를 통해 단순한 접근이 가능하도록 인터페이스를 제공 하고 실제 구현에 대해서는 감추는(캡슐화) 방법을 통해 보안성, 생산성, 품질 등 상당한 이득을 얻을 수 있다고 생각합니다.
    가장 쉬운 예로 자바 언어 자체도 추상화된 결과물 입니다.
    이유는 대표적으로 하드웨어에 대한 접근을 개발자는 신경쓸 필요없이 언어자체적으로 처리해 주기 때문입니다.
  1. 추상화와 인터페이스 차이
  • 이해하신 내용만으로도 충분해 보입니다. 인터페이스는 말그대로 추상화된 연결점이고 이를 각 클래스에서 구현해야 하는데, 모든 클래스에서 각각의 인터페이스를 구현 해야 한다고 하면 어려울 수 있으니 일부메소드(행위)에 대해서 미리 구현해 둔 형태를 추상클래스라고 보시면 될 것 같습니다.
  1. 실제로 많이 사용 되는가?
  • 이미 엄청나게 많이 사용 하셨습니다.
    단적인예로 JDBC Driver의 경우 자바 프로그램 레벨에서는 표준 SQL을 이용한다면 기본적으로 DBMS를 고려하지 않고 개발을 하게됩니다.
    만약 추상화된 드라이버가 없다면?? 어떻게 해야 할까요?
profile
Back-end Developer
post-custom-banner

1개의 댓글

comment-user-thumbnail
2022년 11월 2일

추상화의 의미와 필요성이 확 와닿네요. 좋은 글 감사합니다

답글 달기