저작권 안내: 저작권자표시 Yes 상업적이용 No 컨텐츠변경 No

스프링5 입문

JSP 2.3

JPA 입문

DDD Start

인프런 객체 지향 입문 강의

'추상 클래스'에 해당되는 글 3건

  1. 2013.04.04 GoF 디자인 패턴 1장 요약
  2. 2013.04.04 구상 클래스란 용어의 어색함 (5)
  3. 2012.05.25 객체 지향 기초 이야기 2, 추상화와 다형성 (1)

GoF 패턴 1장 요약한 것

주용 내용:

  • 디자인 패턴의 가치 / 디자인 패턴이란?
  • 주요 개념: 메시지, 인터페이스, 타입, 클래스, 추상/콘크리트 클래스, 상속
  • 디자인 패턴이 풀어주는 것: 객체 역할, 크기, 인터페이스, 구현 등
  • 기본 규칙: 인터페이스 대고 프로그래밍하기, 상속보단 조립을 통한 재사용하기



Posted by 최범균 madvirus

댓글을 달아 주세요

객체 지향 관련 서적을 읽다보면 원서의 'concrete class'를 '구상 클래스'로 번역한 것을 보게 된다. 구상? 뭔가  잘 와닿지 않는다. 왜 이 용어가 어색한걸까? 이 어색함을 풀어보려고 글을 써 본다.


먼저, 이 어색함을 풀어보려면 'concrete class'의 의미를 먼저 알아야 할 것 같다. 'concrete class'는 'abstract class'가 아닌 'class'이인데, 여기서 'abstract class'는 'abstract operation'을 포함하고 있는 클래스를 뜻한다. 'abstract operation'은 시그너쳐만 제공하고 실제 구현(implementation)은 제공하지 않는 'operation'이다. 즉, 'abstract class'는 구현은 제공하지 않는 'operation'을 정의하고 있는 'class'인 것이다. 'concrete class'는 'abstract class'가 아닌 'class'이므로, 'concrete class'란 모든 'operation'이 구현을 제공하는 'class'라고 정의할 수 있을 것 같다.


다시 '구상 클래스'로 돌아가자. '구상'이라는 단어는 실제적이고 구체적이라는 뜻을 같는다. 미술의 경우 '추상 미술'과 '구상 미술'이라는 단어로 초현실적인 것과 현실을 그대로 반영하는 표현기법을 구분해서 표현하기도 한다. 앗, '추상 미술(abstract art)'/'구상 미술(concrete art)', '추상 클래스(abstract class)'/'구상 클래스(concrete class)'? 그러고 보니 '추상'과 '구상'은 쌍을 이루는 단어이다. 영어의 abstract와 concrete가 '추상적인'과 '구체적인(비슷한 의미로는 구상적인)'으로 번역이 되기 때문에, 'abstract class'와 'concrete class'를 각각 '추상 클래스'와 '구상 클래스'로 번역하는 것은 무리가 없어 보인다.


우리가 흔히 사용하는 '추상'과 '구상'이란 단어와 실제 'abstract class'와 'concrete class'의 의미를 함께 생각해보자.

  • 구현을 제공하지 않는 오퍼레이션(메서드)를 갖는 클래스 <--> 추상? 클래스
  • 모든 오퍼레이션이 구현을 제공하는 클래스 <--> 구상? 클래스

소프트웨어에서 '추상화'라는 것은 데이터나 프로세스 등을 의미가 비슷한 개념이나 표현으로 정의하는 것이므로, 추상화를 하면 실제 상세한 구현을 감추고 (더 상위 수준에서 개념적으로) 사고할 수 있는 결과를 얻게 된다. 이런 의미에서 오퍼레이션의 시그너쳐만 정의하고 실제 구현은 제공하지 않는 클래스는 결과적으로 인터페이스와 같은 역할을 하게 되므로 '추상 클래스'라고 표현해도 무난한 듯 하다.


그런데, 'concrete class'는 모든 오퍼레이션이 구현을 제공하는 클래스이다. 즉, 이는 각 오퍼레이션의 실체가 존재한다는 것을 뜻하는 것이다. 구상이라는 것은 추상과 대비되는 말이기 때문에, 뭔가 추상 클래스를 상속한 클래스를 지칭하는 용도로 '구상 클래스'라는 단어를 사용하는 것이 나쁜 선택은 아닌 것 같긴 하지만, 특별히 어떤 추상 타입을 상속받지 않은 클래스를 '구상 클래스'라고 부르기엔 다소 어색함이 있다. 필자의 경우 'concrete class'를 표현할 때 '구현 클래스'라는 단어를 주로 사용해 왔는데, 이 단어 역시 주로 인터페이스를 구현한다는 의미에서 '구현'이라는 단어를 선택한 것이기에 어떤 인터페이스도 상속받지 않은 클래스를 표현하기에는 다소 무리가 있다.


'concrete class'는 실제로 메모리 상에 인스턴스 생성이 가능한 클래스이기 때문에 '실체화 가능 클래스'라고 길게 표현할 수도 있을 것 같긴 한데, 너무 길다. '실체 클래스'는 어떨까? (숨어 있는 범죄 집단 느낌이 나네....) 딱히 뭐라고 표현해야 할지 떠오르지 않는다. 누군가가 언어 감각이 뛰어난 고수분이 'concrete class'를 좀 더 와닿는 용어로 번역해주었으면 하고 바래보면서 글을 마친다.

Posted by 최범균 madvirus

댓글을 달아 주세요

  1. 이대영 2013.04.09 14:09 신고  댓글주소  수정/삭제  댓글쓰기

    저는 코드리뷰나 뭐 대화할대 구현클래스라고 했었던것 같은데.. 또 생각하려니 가물가물 하네용..^^;

  2. 야식 2014.02.26 14:28 신고  댓글주소  수정/삭제  댓글쓰기

    안녕하세요.
    저도 구상클래스라는 말을 보고 검색하다가 따라 들어왔습니다.

    어느 글에서는 '구체' 클래스 라는 용어를 쓰던데요.
    너무 직역한 느낌이 드나요?
    그래도 구체 라는 인스턴스화가 되었다는 뜻도 포함하긴 하는데, 포스팅에서 지적했던 추상을 구현해 내는 느낌은 살짝 부족해 보이긴 합니다.

    아무튼 좋은 생각거리를 해볼 수 있는 기회 주셔서 감사합니다.

  3. 마크 2015.05.02 22:09 신고  댓글주소  수정/삭제  댓글쓰기

    구글에서 구상클래스를 검색해서 들어왔습니다.
    덕분에 개념 이해하고 감니다.
    감사합니다 ^^

  4. 도움받은자 2017.01.15 15:07 신고  댓글주소  수정/삭제  댓글쓰기

    구상 클래스 개념에 대해서 혼동이 있어서 이렇게 찾아와 글을 읽어보니 도움이 되었습니다. 감사합니다.

두 번째로 살펴볼 객체 지향 기초 이야기는 추상화와 다형성에 대한 것이다. 이는 모든 패턴의 기본이 되는 내용이므로 이에 대해 이해하는 것은 무엇보다 중요하다. (아래 내용이 완벽하진 않겠지만 기초가 필요한 분들이 입문하는데에 도움이 되었으면 한다.)

추상화(Abstraction)


추상화Abstraction란? 추상화의 사전적 의미는 특정한 개별 사물과 관련되지 않은 공통된 속성이나 관계 등을 뽑아내는 것이다. 이를 컴퓨터 관점에서 생각해보면, 추상화란 데이터나 프로세스 등을 의미가 비슷한 개념이나 표현으로 정의해 나가는 과정이면서 동시에 각 개별 개체의 구현에 대한 상세함은 감추는 것, 이것이 추상화라고 할 수 있다.

예를 들어, 프로그래밍 언어에서 for, while, foreach 등은 반복을 추상화한 것들이다. 실제로 이것들은 CPU의 이동 명령을 통해서 구현되겠지만, 이 구현으로부터 '반복'이라는 개념을 뽑아내서 for, while 등으로 추상화한 것이다. 비슷하게 OS는 그래픽 기능을 위한 API를 제공하는데, 이 API는 서로 다른 그래픽 카드들의 공통된 기능을 추상화한 결과물이다.

추상화를 하게 되면 상세한 구현이 아닌 공통된 개념과 관계에 집중할 수 있게 되는데, 이는 큰 수준에서 시스템을 이해할 수 있도록 도와준다. 예를 들어, 로그 분석 시스템에서 로그를 다음과 같은 세 가지 방법으로 읽어올 수 있다고 해 보자.
  • 원격 서버의 로그 파일을 FTP로 다운로드한 뒤 로그 조회
  • 원격 서버의 로그 파일을 SCP로 복사한 뒤 로그 조회
  • DB 서버의 로그 테이블로부터 로그 조회
이 세 가지는 개별으로 구현은 다르지만 개념적으로는 '로그 수집'을 처리하는 과정이다. 따라서, 위 세 가지를 '로그 수집'이라는 개념으로 추상화할 수 있으며, 세 개의 상세한 구현이 아닌 한 개의 개념으로 생각할 수 있도록 해 준다.

타입 추상화와 다형성(Polymorphism)

자바에서는 클래스를 이용해서 객체를 표현한다. 예를 들어, FTP 서버로부터 로그 파일을 다운로드해서 로그를 조회하는 객체는 다음과 같은 클래스로 표현할 수 있을 것이다.

public class FtpLogCollector {
    private String ftpServer;
    ... // 기타 다른 필드

    public FtpLogCollector(String ftpServer, String user, String password) {
        this.ftpServer = ftpServer;
        ...
    }

    public FileLogSet collect() {
        ... // FTP에서 파일 다운로드
        ... // 해당 파일의 로그 정보를 담고 있는 FileLogSet 생성 및 리턴
    }
}

FtpLogCollector를 이용해서 로그 정보를 조회하는 코드는 다음과 유사한 형태를 띌 것이다.

FtpLogCollector collector = new FtpLogCollector();
FileLogSet logSet = collector.collect();
FileLogIterator logIter = logSet.iterator();
while (logIter.hasNext()) {
    Log log = logIter.next();
    ...
}
logIter.close();

비슷하게 DB 서버로부터 로그 데이터를 조회하는 객체와 그 기능을 사용하는 객체는 다음과 같은 클래스로 표현될 수 있을 것이다.

public class DBLogCollector {
    private String jdbcUrl;
    ... // 기타 다른 필드

    public DbLogCollector(String jdbcUrl, String user, String password) {
        this.jdbcUrl = jdbcUrl;
        ...
    }

    public JdbcLogSet collect() {
        ... // DB에서 로그 읽어오는 JdbcLogSet 생성 및 리턴
    }
}

DBLogCollector collector = new DBLogCollector();
JdbcLogSet logSet = collector.collect();
JdbcLogIterator logIter = logSet.iterator();
while (logIter.hasNext()) {
    Log log = logIter.next();
    ...
}
logIter.close();

두 코드를 보고나면 너무나도 똑같다는 것을 알 수 있다. 차이점은 FtpLogCollector와 DBLogCollector, FileLogSet과 JdbcLogSet 그리고 FileLogIterator와 JdbcLogIterator의 구현이 다르다는 것일 뿐, 각 클래스가 제공하는 기능은 개념적으로 완전히 동일하다.
  • FtpLogCollector, DBLogCollector : 로그 집합을 특정 자원으로부터 수집하는 기능
  • FileLogSet, JdbcLogSet: 로그에 접근할 수 있는 Iterator를 제공하는 기능
  • FileLogIterator, JdbcLogIterator: 로그를 순차적으로 접근할 수 있는 기능
여기서 추상화의 정의를 다시 살펴보자. 추상화란 데이터나 프로세스 등을 의미가 비슷한 개념이나 표현으로 정의해 나가는 과정이면서 동시에 각 개별 개체의 구현에 대한 상세함은 감추는 것이라고 했다. 이를 위에 맞춰서 설명하면 FTP나 DB에서 로그를 수집하고 파일이나 테이블에 있는 로그에 접근하는 상세한 구현은 감추고 비슷한 개념인 로그 수집과 로그 접근을 도출해내는 것이 추상화인 것이다.

객체 지향 언어에서는 이렇게 추상화된 개념을 인터페이스로 표현한다. 언어마다 인터페이스를 제공하는 방식이 다른데, 자바의 경우 인터페이스를 interface라는 별도 타입으로 제공하고 있으며 또한 추상 클래스(abstract class)를 이용해서 객체의 인터페이스를 정의할 수도 있다. 앞서 로그 수집과 접근 기능을 추상화한 인터페이스는 다음과 같이 정의할 수 있을 것이다.

public interface LogCollector {
    LogSet collect();
}

public interface LogSet {
    LogIterator iterator();
}

public interface LogIterator {
    boolean hasNext();
    Log next();
    void close();
}

객체를 추상화했으면, 그 다음으로 할 작업은 실제 기능을 제공하도록 추상화된 타입을 구현하는 것이다. 자바 언어에서는 상속을 통해서 추상화된 타입을 구현할 수 있도록 하고 있다. interface를 정의한 경우에는 인터페이스 상속인 implements를 이용해서 추상 타입을 구현하게 되고, 추상 클래스를 정의한 경우에는 클래스 상속인 extends를 통해서 추상 타입을 구현하게 된다. 다음은 FTP로부터 로그를 수집해서 로컬 파일에 저장하고 로컬 파일로부터 로그 데이터를 읽어오는 구현을 제공하는 구현의 모습을 보여주고 있다.
 
public class FtpLogCollector implements LogCollector {
    private String ftpServer;
    ...
    public FtpLogCollector(...) { ... }
    public LogSet collect() { ... // FileLogSet을 생성해서 리턴 }
}

public class FileLogSet implements LogSet {
    private List<File> files;

    public LogIterator iterator() { ... FileLogIterator를 생성해서 리턴 }
}

public class FileLogIterator implements LogIterator {
    public boolean hasNext() { ... }
    public Log next() { ... }
    public void close() { ... }
}

위 코드에서 FtpLogCollector, FileLogSet, FileLogIterator는 각각 LogCollector, LogSet, LogIterator가 정의한 기능(메서드)의 실제 구현을 제공하고 있다. JDBC를 사용하는 경우에도 비슷한 구성을 갖게 된다. 즉, FTP로 읽어오기 위해 필요한 구현과 DB에서 읽어오기 위해 필요한 구현이 모두 동일한 인터페이스에 맞춰서 개발되는 것이다.

인터페이스 상속이나 클래스 상속을 통해서 추상화 타입을 구현한다고 해서 모든 게 끝나는 것은 아니다. 이런 추상화가 힘을 발휘할 수 있는 것은 다형성 때문이다. 다형성Polymorphism은 이름 그래도 한 객체가 여러 형태를 갖는다는 의미로 다형성으로 인해 추상화가 빛을 발한다.

다형성을 자바 언어와 연결해 설명해 보자면, 한 클래스의 인스턴스(객체)는 그 클래스가 상속 받은 모든 상위 타입도 될 수 있다는 것이다. 앞의 예제로 다시 한 번 설명해 보자. FtpLogCollector는 LogCollector를 상속받고 있으므로, FtpLogCollector 타입의 객체는 LogCollector로서도 동작할 수 있다. 따라서, 다음과 같은 코드 작성이 가능하다.

LogCollector collector = new FtpLogCollector(....);
LogSet logSet = collector.collect();
LogIterator logIter = logSet.iterator();

FtpLogCollector 객체는 LogCollector 타입도 되기 때문에, 위 코드에서와 같이 FtpLogCollector의 객체를 LogCollector 타입 변수에 할당할 수 있다. 또한, collector.collect()는 실제 객체의 타입인 FtpLogCollector 객체의 collect() 메서드를 실행하게 된다.

위 코드에서 FtpLogCollector를 생성하는 코드를 한 번 더 추상화하면 어떻게 될까?

LogCollector collector = LogCollectorFactory.create();
....

LogCollectorFactory 클래스는 시스템 설정에 따라서 FtpLogCollector나 JdbcLogCollector를 생성해주는 기능을 제공하는 팩토리라고 해 보자. 즉, LogCollectorFactory 클래스는 LogCollector 타입의 객체 생성을 추상화한 클래스이다. 이제 위 코드는 더 이상 특정 LogCollector의 구현체(FtpLogCollector와 같은)에 의존하지 않으며, 오직 추상 타입인 LogCollector만 사용하고 있다. 따라서, FtpLogCollector를 사용하다가 DBLogCollector를 사용하더라도 위 코드는 전혀 영향을 받지 않는다. 오직 LogCollectorFactory만 영향을 받을 뿐이다. 이렇게 실제 사용되는 구현 클래스가 변경되었음에도 불구하고 그 타입을 사용하는 코드가 영향을 받지 않는 것이 바로 다형성으로 인해 가능하다.

추상화란 결국 개발자의 뇌를 위한 것

로그 분석 기능을 생각해보면 큰 덩어리로 '로그 파일을 읽어와 파일을 한줄 한줄 파싱한 뒤 계산해서 내용을 DB에 저장한다'일 것이다. 이런 상세함을 한 번에 다 머리속으로 생각할 수 있는 사람은 많지 않다. (물론, 정말 똑똑한 사람은 한 번에 다 생각할 수 있겠지만..) 그래서 필요한 게 생각이 가능한 수준의 덩어리로 나눠서 생각하는 것이다. 상세한 구현을 생각이 가능한 수준의 덩어리로  만들어나가는 과정이 추상화 과정이며, 이를 통해 개발자는 구현의 상세함 속에서 허우적거리지 않고 (머리속에서) 관리 가능한 수준으로 프로그램과 구현을 다룰 수 있게 된다.

관련글

참고자료


제가 쓴 객체 지향 입문서입니다.


http://www.aladin.co.kr/shop/wproduct.aspx?ISBN=8969090010  에서 확인하실 수 있습니다.



Posted by 최범균 madvirus

댓글을 달아 주세요

  1. 지노 2012.10.23 08:41 신고  댓글주소  수정/삭제  댓글쓰기

    좋은 글 잘 읽었습니다. ^^