지금까지 인터페이스는 메소드만 정의 되는줄 알았습니다. 정적 상수 형태는 인터페이스에서 정의가 가능합니다. C++과 자바 사이에서 혼란을 겪는 혼돈의 시기인가 봅니다.
public interface IMessageProvider {
/**
* Constant for a regular message (value 0).
* <p>
* Typically this indicates that the message should be
* shown without an icon.
* </p>
*/
public final static int NONE = 0;
/**
* Constant for an info message (value 1).
*/
public final static int INFORMATION = 1;
/**
* Constant for a warning message (value 2).
*/
public final static int WARNING = 2;
/**
* Constant for an error message (value 3).
*/
public final static int ERROR = 3;
}
|
2004-04-08 15:40:18.0 (highfive 203.224.101.26) D |
저도 별 생각 없이 static 상수 선언이 안되는줄 알고 있었다가 얼마전 마소의 타이거 관련 기사에서 static import 부분을 보다가 깨달았습니다.
의외로 당연하다고 생각하고 넘어간 데에 함정이 많이 있더군요...
|
2004-04-09 08:53:07.0 (29zu 211.196.185.77) D |
^^; 아.. 의외입니다...(왠지 인간적인면이 보인다는)
저같은 경우엔 C같은 언어도 학교때 하긴했지만 자바를 본격적으로 했기
때문에,C나 C#같은 부분을 볼때자바관점으로 바라보는 경향으로 인해
위의 경우와 같은 차이점을 놓치는 경우가 발생할듯합니다.
(실제 C#보다가 그런적이 있구요)
가끔씩 심심하면 자바책 기초를 훑어보는 경우가 있는데
그때 그동안 잘 몰랐던것을 알게되는경우가 많더라구요.
|
2004-04-09 15:04:21.0 (jini 61.40.188.229) D |
1.5에서 인터페이스에서 필드 정의 가능을 바랬습니다.
아쉽게도 없네요.
공동작업에서 인터페이스로 프레임을 정해주면 매우 편리합니다. 필드도 포함된다면 매우 좋을것 같습니다.
아직 자바는 모르는 부분이 많습니다. 제이랩 유저분들의 많은 조언, 가르침 부탁드립니다.
|
2004-04-21 11:11:35.0 (이너버스 211.108.44.249) D |
인터페이스에서 상수에 final static을 선언 안하셔도 기본적으로 final static 상수로 선언됩니다.
|
2004-04-21 21:29:18.0 (jini 219.248.234.155) D |
그냥 int NONE =0; 이런식으로 써도 되는건가요?
|
2004-04-22 09:57:05.0 (이너버스 211.108.44.249) D |
네.. 그리고 메소드나 멤버변수에 public을 안쓰셔도기본 public입니다.
|
2004-05-20 23:37:37.0 (papilla 220.122.230.33) D |
인터페이스에 필드 정의 기능이 절!대!로!있어서는 안됩니다.
인터페이스란 한 컴포넌트가 다른 컴포넌트를 바라보는 관점을 기술하는 것입니다. 따라서, Interface 설계는역할 정의 작업이라고 할 수 있습니다.
//역할 명
interface 선생{
//역할 지위를 획득하기 위한 조건들
public void 학생을 가르친다();
public void 학생을 교화한다();
}
같은 역할에 대해, 그 역할수행자들에게 가시성을 가진다른 속성이 존재할 수는 없습니다. 왜냐하면 다른 속성이 존재한 다면, 그 속성은 이미 역할과 무관한 문제가 되어버리기 때문입니다!
interface 선생{
private int 하루 식사량;
//역할 지위를 획득하기 위한 조건들
public void 학생을 가르친다();
public void 학생을 교화한다();
}
그냥 보기에도 어처구니가 없지 않습니까? 식사량은 선생이라는 역할을 정의하는데에 있어서 어떠한 일도 수행하지 못합니다. 물론 월급이나 담당과목과 같은 공통 속성을 넣으면 되지 않느냐 하고 반문을 가질 수 있습니다. 하지만 그것은 선생역할을 수행할 수 있는 객체는 담당과목에 대한 데이터를 어떻게 추상화하여 저장해야 하는 것을 "강제"하는 결과를 초래합니다. 이것은 더 이상 다형성과, 로컬라이즈를 지원할 수 없음을 의미합니다. Interface는 단지 역할만을 정의해야 하므로, 구현 내용까지 강제해서는 안되는 것입니다.
역할은 역할을 수행하기 위해 필요한 것들만 제시할 뿐, 그것들의 구현은 자유롭게 풀어 둡니다. 그렇게 하는 것은 재사용성을 최대화며, 자유롭게 구현하게 함으로써 하기 위해서입니다.
ps. 굳이 그것이 필요하다면 그것을 완벽하게 지원 할 수 있는 abstract class가 있습니다. 하지만, 저는 이것의 사용을 완고히 반대하는 바입니다. 이것은 소규모의 프로젝트에서 확고한 다른 장점이 발견될 경우에만 사용해야 하며, 결코 일반화된 문제 해결 도구가 아님을 알아 두셔야 합니다. 이것은 class와 interface의 중간적 존재일 뿐입니다. 또, interface가 static field를 제공하기는 하지만 이것역시 사용해서는 안됩니다. 팔렛트나 폰트처럼 자주 사용되는 값만을 담고 있다 하더라도, 그것은 역할을 구현하는 방법에 간섭을 가지게 되고, 그것은 이 인터페이스와, 이 인터페이스를 구현하는 객체들 사이에 응집성이 존재해버리고 마는 우를 범하게 된다는 뜻이 됩니다.
예를 들어 JTree에 사용되는 트리모델의 트리 노드들이 private ImageIcon같은 것이 존재한다면 Swing차원에서는 굉장히 편리하게 생각될수도 있겠지만, 그것은 시각적 효과를 포함한 Tree모델이 되어 버리는 것이므로, 일반 문제 풀이에 더 이상 트리를 사용할 수 없게 되어버립니다.
|
2004-05-20 23:45:15.0 (jini 219.248.234.149) D |
너무 비약적인 예인것 같습니다. 이런 논리를 전개 하면 모두 안좋은것으로 풀이되겠네요.
"인터페이스란 한 컴포넌트가 다른 컴포넌트를 바라보는 관점을 기술하는 것입니다. 따라서, Interface 설계는역할 정의 작업이라고 할 수 있습니다."
이렇게 정의 내린 사람은 없습니다. 언어에서의 역활은 컴퓨팅 환경과 개발자에 요구에 따라서 변화하는것입니다. 좀더 넓은 마음으로 언어를 대하는것이 어떨까요? 언어의 종류는 다양합니다.
|
2004-05-21 05:51:22.0 (papilla 220.122.230.33) D |
우선 제 입장에서는 너무나 당연한 것이라 논리의 전개가 적절한 형태를 갖추지 못했다는 것을 이해합니다.
1. 왜 interface는 관점인가
다음의 예시를 봐 주세요.
어떠한 someObject가 MouseListener 인터페이스를 구현했다고 가정합시다. 물론 someObject는 MouseListener가 제시한 인터페이스 이외에도 독자적으로 가시성을 가진 기능을 제공하며 메시지에 반응 할 수 있을 것입니다.
그러나 다음의 코드를 봅시다.
MouseListener view = (MouseListener)someObject;
이제부터 view라는 네임을 통하여 MouserListener관점으로 someObject를 바라 보게 됩니다. 따라서 현재 스레드에게 있어 view란 단지 MouseListener의 역할을 수행할수 있는 어떠한 객체 일뿐, someObject의 실체에는 관심도 없을 뿐더러, MouseListener에 제시되지 않은 다른 수행 능력에 대해서는 관심도 없고, 가시성 조차 가지고 있지 않습니다. 심지어는 그러한 관점에 제시된 메시지가 실제로 어떻게 처리되는지 조차도 관심을 가지지 않습니다.
이러한 연유로, interface는 대상 객체에 대한 가시성과 인식을 결정하게 됩니다. 그 인식이란 대상객체가 MouseListener라는 역할자 라는 사실입니다. (UML에서는 Actor라고 부르지만 이것은 해석에 있어 오해의 소지가 많기 때문에 저는 Role Player라고 가르칩니다.) 따라서 interface는 컴포넌트 사이의 관점으로 해석 될 수 있으며, 그것이 interface가 가지는 가장 중요한 속성입니다. interface나 connector의 단어자체가 가진 의미이기도 합니다.
2. 인터페이스가 멤버 필드를 가져서는 안되는 이유
그러면 이제부터 왜 interface가 멤버 필드를 가져서는 안되는 지 설명하겠습니다. 우선은 너무나 당연한 이유가 있습니다. "왜 객체의 속성을 관점의 속성(역할의 속성)에 집어 넣으려고 하는가?" 그러면 다음과 같은 반박을 예상 할 수 있습니다. 이미 클래스나, 추상 클래스에서는 그러한 것을 제공하고 있지 않는가? 단지 같은 역할을 제공한다고 하고 전혀 다른 객체라 할지라도 공통적인 속성을 가질수도 있지 않는가? 그것은 Interface가 관점이라는 사실을 이해하지 못하기 때문에 나오는 반문입니다. 이부분을 명확히 하기 위하여, 실제로 그러한 것들을 제공하는 class와 비교해 보겠습니다. Abstract Class나 Class는 관점 뿐만 아니라 더 많은 것을 제공합니다. 그 관점에 따른 역할의 수행방법까지 명시적으로 제시되곤 하죠. 또 자식에게 멤버 필드를 제공할 수도 있습니다.
2.1 인터페이스와 추상 클래스의 차이
인터페이스와 클래스는 역할이 완전히 다르다는 사실을 알아야만 합니다. 클래스 는 역할을 정의할 뿐만 아니라 역할수행방법까지 명시하고 있습니다. 완벽히 인스턴스에 대해서 규정하고 있는 것입니다. 이것은 interface에 비해 훨씬 더 덜 추상화된 정의 방법이며 훨씬 더 restrict하며 specific합니다.
따라서 "클래스로 부터 상속을 받는 것"은 "그 역할과 역할 수행 방법"을 확장하여, 더 많은 기능이나 특화된 기능을 제공하는 클래스를 만들겠다 라는 의미이며, "인터페이스를 구현하겠다"라는 것은 "해당 인터페이스가 규정하는 역할을 추가적으로 구현 하여 그 역할'도' 획득하겠다"라는 의미인 것입니다. 따라서 인터페이스의 구현이란 추가적 관점의 획득일 뿐으로, 상속 체계상의 요소가 아닌 것입니다. Java는 강력하게 다중상속을 부정하고 있으며, Interface역시 다중 상속을 가능하게 위한 도구일리가 없지요! 잘못된 서적에는 다중상속을 지원하기 위해 Interface가 생겨났다고 하지만, 그것은 고전적 C++ 프로그래머가 생각하는 Interface가 가진 하나의 결과적(derived)속성에 불과할 뿐입니다.
하지만, C++ 은 이러한 interface와 같은 확고한 개념이 생겨나기 전에 등장한 언어였고, 꽤나 미심쩍은 형태인 Abstract Class가 이 일을 대신합니다. 물론 Abstract Class는 인터페이스의 대안으로 사용할 수 있을 뿐만 아니라 멤버 필드도 가질 수 있습니다. 다중 역할 획득 역시 다중 상속이 가능하기 때문에 해결이 됩니다. (물론 상속체계는 난잡해 지지만)
그 이유는 Abstract Class의 기능적 도메인이 Interface를 포함하고 있기 때문입니다. (개념적 도메인은 오히려 더 좁습니다. 많은 것을 제공할수록 적용 분야는 좁아지고, 특화 되지요)
Interface:
역할을 획득하기 위해 반드시 인식할수 있는 메시지들을 명시한다.
→ 제시된 조건을 충족하면 그러한 역할을 수행하는 객체로 볼 수 있다.
Abstract Class:
역할들을 획득하기 위해 반드시 인식할 수 있는 메시지들을 명시한다.
어떠한 메시지의 처리 기법들은 공통적일 수도 있다.
이 역할을 수행하는데에 필요한 일부 멤버 필드들은 동일 할 수도 있다.
→ 제시된 조건중 그 역할 수행기법이 명시되지 않은 메시지에 대하여 상속받은 객체는 반드시 특화된 자기 자신의 역할 수행 방법을 기술해야 한다.
따라서 Abstract Class는 역할 뿐만 아니라, 부분적으로 그 역할 수행 방법까지 제시하고 있습니다. 이것은 단순히 관점만을 보는 것이 아니라, 어떤 역할을 수행함에 있어서 일부분의 방법 자체 역시 제공을 하고 있는 것입니다.
물론 abstract Class는 Interface와 완전히 동일하게 사용할 수도 있습니다. 대신 다른 상속 체계를 선택할수는 없게 되기는 하겠지만요.
2.2 그렇다면 Interface는 왜 abstract class가 가진 기능의 일부를 포기하고도 탄생하게 되었는가?
그렇다면 왜 이러한 특성이 오늘날 필요로 하게 되었는 가를 알아 봅시다. 오늘 날의 소프트웨어는 Jini님이 말씀하신 것처럼 다양한 컴퓨팅 환경 및 믿을 수 없을정도로 다양한 도메인으로 부터, 그 수요가 창출되고 있습니다. 따라서, 각 전문 도메인을 가진 개발팀 구성원간이 커뮤니케이션 방법이 절실하게 요구되었고, 그러한 수요에 따라 등장한 것이 UML과 같은 랭귀지 입니다.
객체 도메인 모델링의 기초는, 일정한 역할을 수행하는 객체들을 같은 공간에 두어 서로 협력하게 하여 결론을 이끌어 낸다는 방식입니다. 이 컴포넌트(객체)들은 각자 인캡슐레이션 되어있으며, 최소한 서로 의사소통하는데에 필요한 관점(Connector)만을 제공 받게 됩니다. 실제 어떤 학생에 대한 정보가 있다 하더라도, 성적 처리 시스템은 그 학생의 취미나 취향에는 관심도 없을 뿐더러, 그러한 관점을 사용하게 되면 overload가 발생합니다. 그래서 학생이라는 관점(interface)로 그 객체를 상대하게 됩니다. 하지만 그 학생은 다른 시스템에서 다른 관점으로 참조 될런지도 모릅니다. 따라서, 그 객체는 다중 역할을 획득하고 있어야 재사용성을 얻을 수 있습니다. 이렇게 함으로써, 각각의 컴포넌트들은 서로 상대방이 어떤식으로 구현되어있으며, 또 얼마나 다른 여러 역할을 수행하고 있는가에 대해서는 아무런 관심을 가지지 않아도 되게 되어, 자기자신에게 주어진 역할들에 충실하면서, 나에게 제공하는 연결된 컴포넌트들의 관점에만 충실하면 되게 됩니다.
이러한 상태에서, 어떤 컴포넌트의 어떤 역할 수행방법이 변경된다 하더라도 ChangeEffect는 거의 일어나지 않게 됩니다. 즉 공동개발이 수월해 질 뿐만 아니라 (거의 CVS 시스템이 따로 필요 없을 정도로!!!) 각 단위는 주어진 관점에서 요구하는 문제 해결에만 주력하면 되게 됩니다. 따라서 각 유닛의 품질은 상승할 뿐만 아니라 cost는 줄어 듭니다.
그러나, 이러한 관점사이에 강제하는 어떠한 멤버 필드가 있다면, 원래는 역할만을 제공만 하면 되었던 루즈한 응집성이, 어떻게 그 역할을 추상화 할 것인가에 대해 어느정도 강제성을 가지게 되어 버리고 맙니다. 왜냐하면 멤버 필드는 단순히 가시성 뿐만이 아니라 그 값에 따른 sematic까지 가질 수 밖에 없기 때문입니다. 따라서 해당 역할에 대한 구조적 이해가 모든 구성원에게 있어야 할 뿐만 아니라, 이러한 관점에서 멤버필드가 수정될 시에, 이를 통해 연결되어있던 컴포넌트는 구조자체가 완전히 흔들려 버리게 되고 맙니다. 결국, 그러한 판단이 서게 될 경우에는, "재설계"에 들어가게 되는 것입니다. 물론 재설계하기 싫다면, interface 대신에 abstract class를 사용하여, 그것이 가능하게끔 할수도 있습니다. 하지만 프로젝트가 진행 될 수록, 이것이 미치는 오차 범위는 걷잡을 수 없을 정도로 확대 될 것이고, 이 시스템 기반위에서 동작할 상위 아키텍처는 거의 예측이 불가능한 오차 확산에 노출 될 것입니다. 거기에 유연성, 확장성, 유지 보수성은 완전히 포기해야 하며 매우 복잡한 CVS알고리즘이 필요해 질 것입니다.
따라서 아무것도 강제하지 않되, 명확한 관점을 제공할 방법이 필요해 지게 된 것 입니다. 그것이 인터페이스 이며, 멤버필드를 포함하지 않는 이유 입니다.
3. 인터페이스 만으로도 부족하다, 인터페이스 조차 강제적 구현을 요구하지 않느냐? 이제는 묵시적 인보킹 시스템 시대이다.
3.1 인터페이스도 부족하다.
그러나 인터페이스라고 해도 그것 자체의 변경이 없다고 assertion할 수는 없습니다. 그러한 경우는 Java에서도 볼 수 있습니다. 디프리케이트 되는 경우가 바로 그러한 예지요. 하지만 이 경우 멤버 필드의 변화만큼 커다란 파급 효과를 가져 오지는 않습니다. 단지 하나나 둘 정도의 메소드 네임이 바뀌거나 바디가 수정되거나, 단지 deprecated 라고 써주면 그만이지요. 물론 멤버 필드가 변경될 경우 구조가 뒤흔들리는 것에 비하면 아주 적은 파급 효과입니다.
그러나 오늘날처럼 복잡한 시스템은 더욱 뛰어난 유연성을 요구하게 됩니다. 그래서 등장한 것이 implict Invocation (Independent Component System)입니다. 인터페이스를 사용한다 하더라도 어떤 한 컴포넌트가 다른 컴포넌트에게 메시지를 전달하려면 인터페이스가 명시한 어떠한 메시지 형태를 따라야만 합니다. 따라서 이 둘 컴포넌트 사이에는 완전한 독립성이 제공되지 못합니다. 즉 어떤 컴포넌트가 어떤 컴포넌트를 활성화 하려면 그 실체에대해서 알지는 못하더라도, 그 역할이 어떻게 규정되어있는가 하는 것은 미리 알고 있어야만 한다는 것입니다.
그래서 등장한 것이 바로 Message-Oriented System입니다. 혹은 Event-driven System이라고도 하지요.
3. 2 Message-Oriented System
예를 들어 JButton에서 액션 이벤트가 발생하면, 그것을 다른 객체가 처리해 줄수도 있습니다. 단지 이 객체에게 요구되는 것은 ActionListener라는 역할을 수행할 수 있는 능력을 가지고 있어라 하는 것 뿐입니다. 또 실제 버튼이 눌릴 때 마다, 프로그래머는 명시적으로 actionPerformed()를 호출해 줄 필요가 없습니다. 이벤트 모델에 의하여 묵시적으로 호출이 이루어 지게 되지요. 두 컴포넌트 사이에는 어떠한 제약도 존재하지 않을 뿐더러, 심지어는 어떤 객체이던지 ActionEvent를 마음껏 발생시킬 수 있습니다.
이제 두 객체사이에 의미를 가진 메시지를 전달하면서도, 아무런 응집성이 존재하지 않게 된 것입니다. (물론 실제로는 프로시져가 호출을 하지만, 상위 추상 레벨에서는 그렇지 않다고 생각하도 무방할 정도로 잘 일반화가 되어있는 것입니다. 이것은 실제적으로 자바가 어떻게 동작하느냐와는 상관이 없습니다. 왜냐하면 이것이 제공하는 sematic layer가 그리하기 때문입니다. 실제로 리눅스의 JVM과 Windows의 JVM은 완전히 다르지만 똑 같은 의미 레이어를 제공하지요. 그것이 가능한 것이 바로 인터페이스의 위력입니다.)
4. 결론
매우 저차원 적인 메시지 전달 방법 과 저수준의 객체간의 통신 수단 및 컴퓨터에만 특화된 이벤트에 대한 개념을 제시하는 C++은 이벤트라고 해봐야 mousePressed 같은게 아니겠느냐 하는 지나치게 컴퓨터적이며 랭귀지적인 사고를 강요하기 쉽습니다.
하지만 자바에서는 buttonPressed가 아니라 actionPerformed라는 용어를 사용하고 있습니다. 이것은, 자바에서의 Event란 환자가 혼수상태에 빠졌다거나, 매물거래가 성행한다거나, 누군가가 죽었다거나 하는 매우 보편적인, 즉 일반화된 이벤트를 추상화하고 있음을 암시하는 대목입니다. 리얼 월드의 문제점을 쉽게 기술하기 위해서는 더욱더 일반화된 개념을 이용하여 구조를 설계하고 개발해야만 합니다. (그럼에도 불구하고 Java의 Event는 modifier같은 컴퓨터적 플래그가 존재합니다. 하지만 이것은 java.awt.*에 속해 있으므로 문제가 되지는 않습니다. 패키지를 통하여 개념을 흩트리지 않고도, 개발편의를 제공할 수 있다는 것이지요)
플랫폼으로의 전이나 최적화는 단지 최종 임플리멘테이션 노가다일 뿐입니다. 만약 그러한 것에 얽매여, 개념적 명확성화 일반화를 포기한다면, 그것은 임플레멘테이션 트랩에 빠지게 되는 것이며, 원래 얻고자 하는 해와는 거리가 먼 곳에서 시간을 낭비하게 될 가능성이 많습니다.
ps. 개발자의 요구와 컴퓨팅 환경에 따라 변화하는 것은 시스템의 구조이어야 하지 역할규명자가 될 수 없습니다. 만약 그렇게 했다면 그것은 객체가 활동하는 역할 도메인을 재정의 하는 것으로, refactoring이나 optimizing에 가까운 최종 임플리멘테이션 테크닉일 뿐으로서, 이미 개발의 영역과 모델링, 추상화가 배제된 deploy 직전의 low-level코드일 뿐입니다. 그것은 최종 전이 단계 직전에 최적화 팀이나, 최적화 툴들이 해야 할 일입니다. 결코 개발자가 해서는 안될 일입니다. 더더군다나 Jini님이 말씀하시는 대로 유동적으로 변화해서 획득된 것이 오늘날의 Java의 Interface입니다.
랭귀지는 도구일 뿐인 하찮은 존재이며, 그 방대함과 유연성은 우리에게 아무런 의미도 없습니다. -어셈블리어가 그러하듯이- ㄱ, ㄴ, ㄷ의 특성과 그것의 조합의 수가 3만개가 넘는 다는 것과는 아무 상관 없이 소설은 씌여집니다. (비록 50개 발음 밖에 없는 일본이라 할지라도) 그러나 자바는 단순히 새로운 랭귀지가 아닌, 위에서 말한 새로운 개념들을 포함하여 새로운 구조적 학문적 기법이 수없이 많이 적용된 새로운 메소돌로지입니다.
어째서 단지 interface에 멤버 필드가 없느냐라고 의문을 가진것에 대해 이렇게까지 격렬한 반응을 가지는지 의문을 가지시고 부디 이것에 대해 연구해 보기를 원합니다.
Java를 단지 새로운 언어로 인식한다면, 굳이 오히려 퍼포먼스와 기능성이 제한된 Java를 사용해야 할 이유가 없습니다.