[JavaScript] 이벤트 등록방법


이벤트 등록방법


1. inline

인라인(inline) 방식으로 이벤트를 등록하는 방법을 알아보자. 인라인 방식은 이벤트를 이벤트 대상의 태그 속성으로 지정하는 것이다.(해당 태그안에 이벤트가 속성으로 직접 들어간 경우)  

다음은 버튼을 클릭했을 때 Hello world를 경고창으로 출력한다.


<input type="button" onclick="alert('Hello world');" value="button" />

이벤트가 발생한 대상을 필요로하는 경우 this를 통해서 참조할 수 있다.

자바스크립트에서 this는 어떤 함수에서 this를 사용한다는 것은  그 함수가 속해있는 객체를 의미(자기 자신을 의미)


<!--자기 자신을 참조하는 불편한 방법-->

<input type="button" id="target" onclick="alert('Hello world, '+document.getElementById('target').value);" value="button" />

<!--this를 통해서 간편하게 참조할 수 있다-->

<input type="button" onclick="alert('Hello world, '+this.value);" value="button" />

this는 이벤트가 동작하고 있는 엘리먼트(input)을 가리킨다. --> 짧고 편리하게 코드를 작성할 수 있다.


인라인 방식은 태그에 이벤트가 포함되기 때문에 이벤트의 소재를 파악하는 것이 편리하다. 하지만 정보인 HTML과 제어인 JavaScript가 혼재된 형태이기 때문에 바람직한 방법이라고 할수는 없다. 


2. 프로퍼티 리스너

프로퍼티 리스너 방식은 이벤트 대상에 해당하는 객체의 프로퍼티로 이벤트를 등록하는 방식이다. 인라인 방식에 비해서 HTML과 JavaScript를 분리할 수 있다는 점에서 선호되는 방식이지만 뒤에서 배울 addEventListener 방식을 추천한다. 

<input type="button" id="target" value="button" />

<script>

    var t = document.getElementById('target');

    t.onclick = function(){

        alert('Hello world');

    }

</script>

t라는 객체중에 onclick(내장됨) 프로퍼티에 정의된 메소드를 실행하게된다. 

 

(1) 이벤트 객체

이벤트가 실행된 맥락의 정보가 필요할 때는 이벤트 객체를 사용한다. 이벤트 객체는 이벤트가 실행될 때 이벤트 핸들러의 인자로 전달된다. 

<body>

    <input type="button" id="target" value="button" />

<script>

    var t = document.getElementById('target');

    t.onclick = function(event){

        alert('Hello world, '+event.target.value)

        // console.dir(event); --> 이벤트에 대한 다양한 정보를 출력한다.

    } --> 이벤트 핸들러

// 익명함수의 첫번째 인자로 event객체를 전달하기로 약속되어 있다. 이벤트 호출될때 event 파라미터를 통해서 현재 발생한 이벤트에 대한 다양한 정보를 얻을 수 있다.

// input button을 클릭하면 이에 해당하는 이벤트 핸들러가 호출된다. 호출시 이벤트 객체(event)를 전달한다. 

// 이 코드에서는 event 객체가 가진 프로퍼티 중에서 target 프로퍼티를 사용한다.

// target 프로퍼티는 이벤트가 호출된 시점에서 그 이벤트가 어디서 발생했는지를 알 수 있게 해주는 프로퍼티이다.

// value는 target이 되는 객체의 value 값을 말한다. 여기서는 value="button" 이다.

</script>

실행결과)

Hello world, button


ie8 이하 버전에서는 이벤트 객체를 핸들러의 인자가 아니라 전역객체의 event 프로퍼티로 제공한다. 또한 target 프로퍼티도 지원하지 않는다. 아래는 이 문제를 해소하기 위한 코드다.

<input type="button" id="target" value="button" />

<script>

    var t = document.getElementById('target');

    t.onclick = function(event){

        var event = event || window.event;// window.event는 IE 브라우저의 이벤트 프로퍼티(크로스 브라우징)

        var target = event.target || event.srcElement;

        alert('Hello world, '+target.value)

    }

</script>


3. addEventListener()

addEventListener은 이벤트를 등록하는 가장 권장되는 방식이다. 이 방식을 이용하면 여러개의 이벤트 핸들러를 등록할 수 있다.

<input type="button" id="target" value="button" />

<script>

    var t = document.getElementById('target');

    t.addEventListener('click', function(event){// click 이벤트 발생시, 두번째 인자의 함수가 실행된다.

        alert('Hello world, '+event.target.value);//프로퍼티 리스너 유사(두번째 인자)

    });

</script>

이 방식은 ie8이하에서는 호환되지 않는다. 


ie에서는 attachEvent 메소드를 사용해야 한다. jQuery를 사용하면 호환성 문제 해결된다.

var t = document.getElementById('target');

if(t.addEventListener){//false=undefinded

    t.addEventListener('click', function(event){

        alert('Hello world, '+event.target.value);

    }); 

} else if(t.attachEvent){//addEventListener이 없다면 attachEvent를 사용한다.

    t.attachEvent('onclick', function(event){//attachEvent는 onclick

        alert('Hello world, '+event.target.value);

    })

}


이 방식의 중요한 장점은 하나의 이벤트 대상에 복수의 동일 이벤트 타입 리스너를 등록할 수 있다는 점이다. 

addEventListner는 이벤트를 덮어쓰는 것이 아니라 add해주는 것이라서 복수로 사용이 가능한다.

뒷 단원 캡처링과 버블링이란 개념은 이벤트 전파 방식도 복수의 이벤트가 설치될 경우를 전제로 하므로 addEventListener로 이벤트 등록 방식을 사용할 경우에만 해당한다.

<input type="button" id="target" value="button" />

<script>

    var t = document.getElementById('target');

    t.addEventListener('click', function(event){

        alert(1);

    });

    t.addEventListener('click', function(event){

        alert(2);

    });

</script>

프로퍼티 리스너 방식은 하나만 실행된다.--> 위 예제에서는 '2'(alert)만 실행된다.


이벤트 객체를 이용하면 복수의 엘리먼트에 하나의 리스너를 등록해서 재사용할 수 있다. 

<input type="button" id="target1" value="button1" />

<input type="button" id="target2" value="button2" />

<script>

    var t1 = document.getElementById('target1');

    var t2 = document.getElementById('target2');

    function btn_listener(event){ // btn_listener는 이벤트 리스너로 사용될 함수이다.

        switch(event.target.id){// 각각 event 객체로 전달된 target 프로퍼티에서 id의 값을 알 수 있다.

            case 'target1':

                alert(1);

                break;

            case 'target2':

                alert(2);

                break;

        }

    }

    t1.addEventListener('click', btn_listener); // click시 t1의 식별자로 btn_listener 이벤트가 실행된다.

    t2.addEventListener('click', btn_listener); // click시 t2의 식별자로 btn_listener 이벤트가 실행된다.

    // 이제 버튼 2개를 이용하여 하나의 이벤트 핸들러로 이벤트를 처리할 수 있다.--> 많은 코드를 재활용할 수 있다.

</script>



'WebFont-end > JavaScript' 카테고리의 다른 글

[JavaScript] 이벤트 타입  (0) 2014.12.25
[JavaScript] 이벤트  (0) 2014.12.25
[JavaScript] Text 객체  (0) 2014.12.23
[JavaScript] Document 객체  (0) 2014.12.23
[JavaScript] Node 객체  (1) 2014.12.23

[JavaScript] 이벤트


이벤트


1. 이벤트란?

이벤트(event)는 어떤 사건을 의미한다. 브라우저에서의 사건이란 사용자가 클릭을 했을 '때', 스크롤을 했을 '때', 필드의 내용을 바꾸었을 '때'와 같은 것을 의미한다. 

<!DOCTYPE html>

<html>

<body>

    <!-- 사용자가 클릭했을 때 자바스크립트 함수 실행 -->

    <input type="button" onclick="alert(window.location)" value="alert(window.href)" />

    <input type="button" onclick="window.open('bom.html')" value="window.open('bom.html')" />

</body>

</html>

onclick 속성의 자바스크립트 코드(alert(window.location))는 사용자가 이 버튼을 클릭 했을 '때' 실행된다. 즉 js 개발자는 어떤 일이 발생했을 때 실행 되어야 하는 코드를 등록하고, 브라우저는 그 일이 발생했을 때 등록된 코드를 실행하게 된다. 이러한 방식을 이벤트 프로그래밍이라고 한다.


(1) event target

target은 이벤트가 일어날 객체(button)를 의미한다. 아래 코드에서 타겟은 버튼 태그에 대한 객체가 된다.

<input type="button" onclick="alert(window.location)" value="alert(window.href)" />


(2) event type

이벤트의 종류를 의미한다. 위의 예제에서는 click이 이벤트 타입이다. 그 외에도 scroll은 사용자가 스크롤을 움직였다는 이벤트이고, mousemove는 마우스가 움직였을 때 발생하는 이벤트이다.

이벤트의 종류는 이미 약속되어 있다. 아래 링크는 브라우저에서 지원하는 이벤트의 종류를 보여준다.

https://developer.mozilla.org/en-US/docs/Web/Reference/Events


(3) event handler

이벤트가 발생했을 때 동작하는 코드를 의미한다. 위의 예제에서는 alert(window.location)이 여기에 해당한다. 일반적으로 함수에 많이 쓰인다.


2. 이벤트 핸들러 종류


cf.)

이벤트 타입: click

이벤트 속성: onclick

이벤트 핸들러: whenClick() / 이벤트 타입에 해당하는 이벤트가 발생했을 때 실행되는 함수.

--> 문서 객체에 이벤트에 연결하는 방법을 이벤트 모델이라고 한다.


 이벤트 핸들러

 이벤트 내용

 onclick

 클릭할 때

 ondblclick

 더블클릭할 때

 onkeydown

 키를 눌렀을 때

 onkeypress

 키를 누르고 있을 때

 onkeyup

 눌러진 키를 원래대로 되돌릴 때

 onmousedown

 마우스 버튼을 눌렀을 때

 onmouseup

 마우스 버튼을 뗄 때

 onmouseover

 마우스 포인터가 통과할 때

 onmouseout

 마우스 포인터가 벗어날 때

 onmouse

 마우스 포인터가 이동할 때

 onload

 페이지 읽어올 때

 onunload

 다른 페이지로 이동할 때

 onfocus

 폼 부품이나 창에 초점이 맞춰질 때

 onblur

 폼 부품이나 창으로부터 초점이 벗어날 때

 onsubmit

 폼이 송신될 때

 onreset

 리셋 버튼을 눌렀을 때

 onchange

 입력란의 문자열이나 메뉴에서 선택한 항목에 변화가 있을 때

 onsize

 창의 크기가 변경될 때

 onmove

 창이 이동될 때

 onabor

 그림 읽기를 중단했을 때

 onerror

 파일이 존재하지 않거나 그림 읽기에 실패했을 때

 onselect

 입력란의 문자열이 선택될 때


3. 이벤트 전파(버블링과 캡처링)

캡처링과 버블링이란 개념은 이벤트 전파 방식도 복수의 이벤트가 설치될 경우를 전제로 하므로 addEventListener로 이벤트 등록 방식을 사용할 경우에만 해당한다.
HTML 태그는 중첩되어 있다. 따라서 특정한 태그에서 발생하는 이벤트는 중첩되어 있는 태그들 모두가 대상이 될 수 있다. 이런 경우 중첩된 태그들에 이벤트가 등록 되어 있다면 어떻게 처리 될까? 


<html>
    <head>
        <style>
            html{border:5px solid red;padding:30px;}
            body{border:5px solid green;padding:30px;}
            fieldset{border:5px solid blue;padding:30px;}
            input{border:5px  solid black;padding:30px;}
        </style>
    </head>
    <body>
        <fieldset>
            <legend>event propagation</legend>
            <input type="button" id="target" value="target">          
        </fieldset>
        <script>
        function handler(event){
            var phases = ['capturing', 'target', 'bubbling']
            console.log(event.target.nodeName, this.nodeName, phases[event.eventPhase-1]); //nodeName:input
        }
        document.getElementById('target').addEventListener('click', handler, true);
        document.querySelector('fieldset').addEventListener('click', handler, true);
        document.querySelector('body').addEventListener('click', handler, true);
        document.querySelector('html').addEventListener('click', handler, true);
        </script>
    </body>
</html>
실행결과)
INPUT HTML capturing
INPUT BODY capturing
INPUT FIELDSET capturing
INPUT INPUT target 

event.target.nodeName:INPUT ==> target은 언제나 <input> 태그를 가리킨다. 여러 계층속에서 가장 구체적인 태그가 target이다.
this.nodeName:FIELDSET ==> 이벤트 핸들러가 호출된 태그이다.
phase[event.eventPhase-1]:capturing ==> 부모태그에서 자식태그로 이벤트가 호출되는 방식

이벤트 핸들러가 설치되는 순서: html -> body -> fieldset -> input
--> click 이전의 단계로 document.querySelector('html').addEventListener('click', handler, false); 와 같은 기술 순서와 무관함을 혼동하지 말자.

이벤트가 부모에서부터 발생해서 자식으로 전파되고 있다. 이러한 방식을 capturing이라고 한다. ie 낮은 버전에서는 작동하지 않기 때문에 많이 사용하지는 않는다.

코드를 아래와 같이 변경해보자.
document.getElementById('target').addEventListener('click', handler, false); //false면 버블링으로 변환 
document.querySelector('fieldset').addEventListener('click', handler, false);
document.querySelector('body').addEventListener('click', handler, false);
document.querySelector('html').addEventListener('click', handler, false);
실행결과)
INPUT INPUT target
INPUT FIELDSET bubbling
INPUT BODY bubbling
INPUT HTML bubbling
차이점은 addEventListener의 3번째 인자가 false로 변경 되었다.
이벤트 핸들러가 설치되는 순서가 이전 코드와 반대로 되어 있다.

이번에는 순서가 반대로 되었다. 자식부터 부모로 이벤트가 전파되는 것을 버블링(bubbling)이라고 한다.
이벤트 전파를 중간에 가로막을 수도 있다.
아래처럼 코드를 변경해보자. 
function handler(event){
    var phases = ['capturing', 'target', 'bubbling']
    console.log(event.target.nodeName, this.nodeName, phases[event.eventPhase-1]);
}
function stophandler(event){
    var phases = ['capturing', 'target', 'bubbling']
    console.log(event.target.nodeName, this.nodeName, phases[event.eventPhase-1]);
    event.stopPropagation();
}
document.getElementById('target').addEventListener('click', handler, false);
document.querySelector('fieldset').addEventListener('click', handler, false);
document.querySelector('body').addEventListener('click', stophandler, false);
document.querySelector('html').addEventListener('click', handler, false);
실행결과)
INPUT INPUT target
INPUT FIELDSET bubbling
INPUT BODY bubbling
INPUT HTML bubbling
참고로 ie9 이전의 브라우저에서는 이벤트 전파을 막기 위해서 event.cancelBubble 프로퍼티를 사용해야 한다.

이벤트 전파가 html로 가지 않고 body에서 멈추었다.

4. 기본동작의 취소
웹브라우저의 구성요소들은 각각 기본적인 동작 방법을 가지고 있다.
- 텍스트 필드에 포커스를 준 상태에서 키보드를 입력하면 텍스트가 입력된다.
- 폼에서 submit 버튼을 누르면 데이터가 전송된다.
- a 태그를 클릭하면 href 속성의 URL로 이동한다.
- 이러한 기본적인 동작들을 기본 이벤트라고 하는데 사용자가 만든 이벤트를 이용해서 이러한 기본 동작을 취소할 수 있다.

(1) inline
이벤트의 리턴값이 false이면 기본 동작이 취소된다.
<p>
    <label>prevent event on</label><input id="prevent" type="checkbox" name="eventprevent" value="on" />
</p>
<p>
    <a href="http://opentutorials.org" onclick="if(document.getElementById('prevent').checked) return false;">opentutorials</a>
</p><!--if 조건문이 true라면 return false -->
<p>
    <form action="http://opentutorials.org" onsubmit="if(document.getElementById('prevent').checked) return false;">
            <input type="submit" /><!-- onsubmit: submit(submit 클릭시) 했을때 발생하는 이벤트이다. -->
    </form>
</p>

(2) property 방식
리턴 값이 false이면 기본동작이 취소된다. 
<p>
    <label>prevent event on</label><input id="prevent" type="checkbox" name="eventprevent" value="on" />
</p>
<p>
    <a href="http://opentutorials.org">opentutorials</a>
</p>
<p>
    <form action="http://opentutorials.org">
            <input type="submit" />
    </form>
</p>
<script>
    document.querySelector('a').onclick = function(event){
        if(document.getElementById('prevent').checked)<!-- true 라면 return false-->
            return false;
    };
     
    document.querySelector('form').onclick = function(event){
        if(document.getElementById('prevent').checked)
            return false;
    };
</script>

(3) addEventListener 방식
이 방식에서는 이벤트 객체의 preventDefault 메소드를 실행하면 기본 동작이 취소된다. 
<p>
      <label>prevent event on</label><input id="prevent" type="checkbox" name="eventprevent" value="on" />
</p>
<p>
      <a href="http://opentutorials.org">opentutorials</a>
</p>
<p>
       <form action="http://opentutorials.org">
             <input type="submit" />
       </form>
</p>
<script>
       document.querySelector('a').addEventListener('click', function(event){
              if(document.getElementById('prevent').checked)
              event.preventDefault();
        });
             
        document.querySelector('form').addEventListener('submit', function(event){
             if(document.getElementById('prevent').checked)
             event.preventDefault();
        }); 
</script>
ie9 이하 버전에서는 event.returnValue를 false로 해야 한다. 


'WebFont-end > JavaScript' 카테고리의 다른 글

[JavaScript] 이벤트 타입  (0) 2014.12.25
[JavaScript] 이벤트 등록방법  (0) 2014.12.25
[JavaScript] Text 객체  (0) 2014.12.23
[JavaScript] Document 객체  (0) 2014.12.23
[JavaScript] Node 객체  (1) 2014.12.23

[Java] for-each문


for-each문


배열과 컬렉션에 저장된 요소에 접근하기 할 때 기존보다 편리한 방법으로 처리할 수 있도록 for문의 새로운 문법이 추가되었다.


1. 배열

for(배열의 타입 변수명 : 배열){

// 반복할 문장

}


2. 컬렉션

for(컬렉션에 저장된 요소의 타입 변수명 : 컬렉션){

// 반복할 문장

}


3. 배열 예제

아래의 두 for문은 서로 동일하다.

int [] arr = {10, 20, 30, 40 50};


for(int i = 0; i<arr.length; i++;){

System.out.println(arr[i]);

}


for(int i : arr){// arr[i]가 아닌 i라는 것에 유의

System.out.println(i);

}

코드 해석: 반복문이 한 번 반복될 때마다 변수 e에 컬렉션 arr의 인덱스가 하나씩 저장되며, e에 저장된 원소와 한 칸의 공백을 출력한다. 반복은 배열의 인덱스 0부터 n-1까지 이루어진다. (배열 자체는 참조만 되기 때문에 변경되지 않음)



4. 컬렉션 예제

이제 ArrayList에 저장된 요소들에 접근하기 위해 for문을 사용한다면 다음과 같을 것이다.

ArrayList<Integer> list = new ArrayList<Integer>();

list.add(new Integer(10));

list.add(new Integer(20));

list.add(new Integer(30));

list.add(new Integer(40));

Iterator it = list.iterator();


for(it.Iterator();){

System.out.println(it.next());

}


for(Integer i : list){

System.out.println(i);

}


'Programing > Java' 카테고리의 다른 글

[Java] 예외 처리 기본  (0) 2014.12.25
[Java] enum  (0) 2014.12.25
[Java] 오토박싱  (0) 2014.12.23
[Java] 익명클래스  (0) 2014.12.23
[Java] public static void main(String [] args)  (0) 2014.12.23

[Java] 오토박싱


오토박싱


컬렉션에는 객체로 저장해야하기 때문에 기본형 값을 저장하기 위해서는 Integer나 Long과 같은 Wrapper클래스를 사용해야 했다.

그러나 이제부터는 기본형 값을 직접 컬렉션에 저장할 수 있다. 컴파일러에 의해서 자동적으로 Wrapper클래스로 변환되어 저장되는데 이것을 오토박싱이라고 한다.

뿐만 아니라 저장된 값을 꺼낼 때도 변환과정을 거치지 않고도 기본형 형태의 값을 바로 얻을 수 있는데 이것을 언박싱이라고 한다.


ArrayList list = new ArrayList();

list.add(new Integer(10));

list.add(new Integer(20));

list.add(new Integer(30));

Integer i =(Integer)list.get(0);

int value = i.intValue();


이전에는 위와 같은 코드를 사용했지만 이제는 아래와 같이 코드를 간략히 할 수 있다.

ArrayList<Integer> list = new ArrayList<Integer>();

list.add(10);// 오토박싱

list.add(20);// 오토박싱

list.add(30);// 오토박싱

int value = list.get(0);// 언박싱


'Programing > Java' 카테고리의 다른 글

[Java] enum  (0) 2014.12.25
[Java] for-each문  (0) 2014.12.23
[Java] 익명클래스  (0) 2014.12.23
[Java] public static void main(String [] args)  (0) 2014.12.23
[Java] 인터페이스  (0) 2014.12.23

[Java] 익명클래스


익명 클래스


익명 클래스는 특이하게도 다른 내부 클래스들과 달리 이름이 없다. 클래스의 선언과 객체의 생성을 동시에 하기 때문에 단 한번만 사용될 수 있고 오직 하나의 객체만을 생성할 수 있는 일회용 클래스이다. 이름이 없기 때문에 생성자도 가질수 없으며, 조상클래스의 이름이나 구현하고자 하는 인터페이스의 이름을 사용해서 정의하기 때문에 하나의 클래스로 상속받는 동시에 인터페이스를 구현하거나 둘 이상의 인터페이스를 구현할 수 없다. 오로지 단 하나의 클래스를 상속받거나 단 하나의 인터페이스만을 구현할 수 있다.


class InnerEx6 {

Object iv = new Object(){ void method(){} }; // 익명클래스

static Object cv = new Object(){ void method(){} }; // 익명클래스


void myMethod() {

Object lv = new Object(){ void method(){} }; // 익명클래스

}

}

실행결과)

InnerEX6.class

InnerEX6$1.class(익명 클래스)

InnerEX6$2.class(익명 클래스)

InnerEX6$3.class(익명 클래스)

익명클래스는 이름이 없기 때문에 '외부클래스명$숫자1.class' 형식으로 클래스파일명이 결정된다.


import java.awt.*;

import java.awt.event.*;


class InnerEx7

{

public static void main(String[] args) 

{

Button b = new Button("Start");

b.addActionListener(new EventHandler());

}

}


class EventHandler implements ActionListener

{

public void actionPerformed(ActionEvent e) {

System.out.println("ActionEvent occurred!!!");

}

}


import java.awt.*;

import java.awt.event.*;


class InnerEx8

{

public static void main(String[] args) 

{

Button b = new Button("Start");

b.addActionListener(new ActionListener() {

public void actionPerformed(ActionEvent e) {

System.out.println("ActionEvent occurred!!!");

}

} // 익명 클래스의 끝

);

} // main메서드의 끝

} // InnerEx8클래스의 끝

앞의 예제에서 익명클래스를 이용해서 변경한 것이 바로 밑의 예제이다. 먼저 두 개의 독립된 클래스를 작성항 다음에, 다시 익명 클래스를 이용하여 변경하면 보다 쉽게 코드를 작성할 수 있다.


'Programing > Java' 카테고리의 다른 글

[Java] for-each문  (0) 2014.12.23
[Java] 오토박싱  (0) 2014.12.23
[Java] public static void main(String [] args)  (0) 2014.12.23
[Java] 인터페이스  (0) 2014.12.23
[Java] 인터페이스와 다형성  (1) 2014.12.21

[Java] public static void main(String [] args)


public static void main(String[] args)


- 메인 메서드는 진입점(Entry Point)을 뜻한다. 그러므로 메인 메서드의 접근자는 항상 public 이어야 한다. --> public


- 메인 메서드는 항상 정적이어야 한다. 클래스는 메모리에 로딩된 다음에 사용이 가능하다. static이 붙은 클래스나 메서드, 변수는 컴파일시 자동으로 로딩된다. 메인 메서드는 클래스 로딩 없이 호출할 수 있어야 한다. 그렇기 때문에 static을 사용한다. --> static


- void는 리턴타입이 없다는 뜻이다. 메인 메서드는 Entry Point이면서 프로그램의 끝이기도 하다. 메인으로 시작해서 메인이 끝나면 그 프로그램도 끝이다. 그러므로 리턴하는 값 자체가 불필요하다. 프로그램이 끝났는데 마지막에 어떤 값을 리턴해봤자 아무 의미가 없기 때문이다. --> void

 

- String[] args 는 프로그램 실행시 매개변수를 보내서 실행할 수 있다는 것을 뜻한다. 1개를 사용할수도 있고 여러개를 사용할 수도 있기 때문에 배열을 사용한다.


cf.) public과 static은 순서가 바뀌어도 상관없다. 하지만 void는 리턴타입이므로 반드시 메서드 명 앞에 와야 한다.

 public static void main(String[] args){}

 static public void main(String args[]){}


'Programing > Java' 카테고리의 다른 글

[Java] 오토박싱  (0) 2014.12.23
[Java] 익명클래스  (0) 2014.12.23
[Java] 인터페이스  (0) 2014.12.23
[Java] 인터페이스와 다형성  (1) 2014.12.21
[Java] 다형성  (0) 2014.12.21

[Comparison] 추상메서드와 인터페이스


추상메서드와 인터페이스


1. 공통점

1) 둘 다 모두 추상 메소드라는 것을 가진다. 구현 클래스에서는 반드시 만들어야만하는 강제성을 가진다. 또한 추상 메소드는 컴파일러를 속인다. 

추상 클래스는 변수를 인터페이스나 부모 클래스 타입으로 보았을 때 아무런 호출에 문제를 일으키지 않는다. 

따라서 컴파일러는 실제로 메소드가 어떻게 동작할지는 모르고, 아무 문제 없이 실행해준다. 즉 컴파일러를 속여서 내가 원하는 동작을 마음대로 조종하게 한다는 것이다.


2) 둘 다 객체 생성은 불가능하고, 타입으로만 사용된다.

추상 클래스와 인터페이스 둘 다 객체의 생성이 목적인 클래스가 아니라. 변수나, 파라미터, 리턴 타입, 자료구조를 유연하게 쓰기 위한 도구이다.


2. 차이점

1) 인터페이스는 스펙이나 원하는 기능을 정의하고자 쓰지만, 추상 클래스는 ‘상속+강제성’이 목적이다.

인터페이스각 객체 간의 통신을 위해서 사용되는 반면에 추상 클래스는 본연의 상속 기능에 강제성을 추가하는 것이 목표로, 만들어진 시작점이 다르다는 것이다.


2) 인터페이스는 상수, 추상 메소드만 존재하지만, 추상 클래스는 상속이 원래 목적이므로 실제 변수나 메소드를 그대로 가지고 있다.

인터페이스는 상호 간의 규칙이기 때문에 private으로 변수를 선언할 수도 없고 선언된 변수는 자동으로 상수로 처리된다. 반면에 추상 클래스는 상속의 수단이기 때문에 상속의 본연의 기능을 그대로 가지고 있다. 따라서 공통적인 메소드나 변수를 부모 클래스로 모아서 사용할 수 있다.


3) 인터페이스는 부채만 남겨주지만, 추상 클래스는 재산도 남겨 준다. 인터페이스는 추상 메소드만 존재하기 때문에 부채만 잔뜩 던져주게 되지만 추상 클래스는 상속의 원래 기능을 그대로 사용할 수 있다는 얘기이다.


4) 인터페이스는 다중 상속도 가능하지만, 추상 클래스는 단일 상속만 된다. 추상 클래스는 상속이 본 목적이므로 기존 상속처럼 단일 상속만 가능하다.


[Java] 인터페이스


인터페이스


1. 인터페이스란?

인터페이스는 일종의 추상클래스이다. 인터페이스는 추상클래스처럼 추상메서드를 갖지만 추상클래스보다 추상화 정도가 높아서 추상클래스와 달리 몸통을 갖춘 일반 메서드 또는 멤버변수를 구성원으로 가질 수 없다.

오직 추상메서드와 상수만을 멤버로 가질 수 있으며, 그 외의 다른 어떠한 요소도 허용하지 않는다.

추상클래스를 부분적으로만 완성된 '미완성 설계도'라고 한다면, 인터페이스는 구현된 것은 아무 것도 없고 밑그림만 그려져 있는 '기본 설계도'라 할 수 있다. 인터페이스도 추상클래스처럼 완성되지 않은 불완전한 것이기 때문에 그 자체만으로 사용되기 보다는 다른 클래스를 작성하는데 도움 줄 목적으로 작성된다.


cp.) 인터페이스란 무엇인가

사전적 의미는 어떤 객체와 객체의 중간에 놓이는 것(객체와 객체의 중간에 놓이는 통신 채널)


1) 인터페이스는 뭐 할 때 쓰는 건가?

둘이서 서로 다른 클래스를 만들 때 서로 ‘이렇게 만들자, 이렇게 만들어 드릴게요’라면서 약속할 때 쓰이는 것이 인터페이스이다. 즉 클래스를 만들기 전에 앞으로 이런 기능을 만들겠다. 이런 기능이 있었으면 좋겠다고 먼저 합의해놓은 것이 인터페이스이다.


2) 인터페이스는 어떻게 쓰는 것인가?

먼저 필요한 약속을 먼저 잡고, 한쪽에서 약속대로 호출하고, 한쪽에서는 약속대로 구현대로 사용한다. 인터페이스를 구현하는 입장에서는 약속한 대로 기능(메소드)을 만들어주고, 사용하는 입장에서는 실제 객체가 어떻든 간에 약속을 이행할 수 있는 객체이기만 한다면 마음대로 약속된 기능을 호출하는 방식이다.


3) 인터페이스는 새로운 기능인가?

프로그램을 설계하고 조금 더 유연한 프로그램을 만드는 기법이다. 인터페이스는 상속과 더불어서 다형성이라는 객체지향 프로그래밍의 특징을 구현하는 방식이다.


2. 인터페이스를 사용하는 상황

(1) 당신과 친구가 서로 약속을 한다면: 객체의 스펙

A가 사용할 객체를 만들어준다면 아마도 B는 A가 프로그래밍이 다 완료될 때까지 기다리고 있어야만 한다. 처음부터 A가 어떤 메소드를 만들 것인지를 먼저 정하는 것이다. 어떤 메소드에는 어떤 파라미터를 받게 할 것이고, 어떤 메소드에는 어떤 리턴값을 이용할 것이다 등 이런 논의를 먼저하게 되면 B는 적어도 A가 만든 클래스와 객체가 어떤 메소드를 가졌는지 알게 되고, 바로 당장은 아니더라도 프로그램을 개발하는데 도움이 될 것이다.

우리가 해야 하는 일은 정확하게 구분하고, 상대방에 해야 할 일을 명시해주는 작업을 해야 한다면 인터페이스를 이용해야 한다고 생각하면 된다. 이러한 의미에서 인터페이스는 일종의 객체의 계약서(스펙)라는 의미가 있다.


(2) 오늘 점심 뭐 먹지?: 스펙을 만족하는 객체

여러 객체 중에서 여러분이 원하는 기능을 가진 객체의 스펙을 만족하게 한다는 객체를 만들어주고자 하는 것이 인터페이스이다. 즉 어떤 객체가 여러분이 선택한 기준의 기능들을 다 구현하고 있다고 생각하면 된다.

따라서 인터페이스를 구현한다는 의미는 어떤 객체가 어떤 기준을 만족하게 한다는 의미로 해석할 수 있다.

(입사 기준에 만족하는 사람은 여러 명이 있을 수 있다. 실행활에서 어떤 기준을 만족하듯이 객체들이 어떤 기준을 만족하게 하는 장치가 바로 인터페이스의 용도 중의 하나이다.)


(3) 꿩 대신 닭: 현재 객체의 대체물

프로그래밍에서는 어떤 기준에 만족한 객체를 이용해서 프로그래밍을 만들다가 새로운 버전이나 다른 객체로 변경하는 일도 자주 일어난다. 이럴 때 기존의 메소드를 전면 수정하게 되면 결국은 모든 코드의 내용을 수정해야 하는 일이 발생한다.

인퍼페이스를 이용한다는 것은 인터페이스를 구현한 객체들을 하나의 부속품처럼 마음대로 변경해서 사용하는 것이 가능하다는 것이다.

자동차의 순정부품이 있긴 하지만, 때로는 다른 부품을 결합하기도 하는 것처럼, 인터페이스는 시스템이 확장되면서 발생하는 잦은 변경의 문제를 해결하는 데 사용한다.

--> 인터페이스를 코드에 적용하게 되면 실제 객체의 클래스를 몰라도 프로그램을 코딩할 수 있다. 따라서 더 유연한 프로그램을 설계할 수 있다.


(4) 호텔 떡볶이와 길거리 떡볶이: 전혀 다른 객체의 같은 기능

실제로 시내의 모 호텔에 갔더니 떡볶이를 파는 상황을 그려보자.

떡볶이는 길거리 음식이라고 생각했는데 버젓이 호텔의 메뉴판에 있는 것이다. 호텔 요리사와 노점에서 장사하는 사람, 이 두사람은 서로 다른 객체이지만 같은 기능을 할 수 있는 존재들이다. 즉 필요하다면 위에서 말한 하나의 부속품처럼 두 객체를 시스템에서 마음대로 사용할 수 있어야만 한다.

인터페이스는 하나의 기능에 대한 약속이기 때문에 중요한 점은 어떤 객체이든 간에 그 약속을 지키기만 한다면 필요한 곳에서 사용할 수 있게 한다는 것을 의미한다.


3. 문법으로 알아보는 인터페이스

(1) 인터페이스는 실제 객체를 의미하지 않는다.

인터페이스는 그 자체가 객체를 의미하지 않는다. 인터페이스라는 것은 결국은 어떤 객체가 할 수 있는 기능 자체를 의미하고, 그 기능을 하나의 스펙으로 모은 것에 불과하다. 따라서 인터페이스가 실제 기능을 가지는 것이 아니다. 즉 실제로 구현된 코드를 가지지 않았다는 것이다. 인터페이스는 실제로 구현된 코드 대신에 오로지 추상 메소드와 상수만을 가지고 있게 된다.


(2) 인터페이스의 상수는 private으로 만들 수 없다.

인터페이스는 실제 객체는 아니지만 서로 간의 약속으로 사용된다. 정해진 약속을 한 쪽에서 일방적으로 수정하게 되면 문제가 발생할 수 있다. 인터페이스는 객체와 객체의 중간에 놓이기 때문에 인터페이스에 선언하는 변수는 자동으로 'public static final'이 된다. 즉 완벽한 상수로 정의된다. 반면에 private는 객체를 만들 때 외부 클래스에서 접근할 수 없게 하려고 사용하기 때문에 외부로 공개되기 위해서 사용하는 인터페이스에는 맞지 않는다. 그래서 실제로 인터페이스에 private으로 시작하는 변수는 선언할 수 없다.


(3) 인터페이스에는 추상 메소드만 존재한다.

인터페이스는 실제 객체로 만들어지지 않는다. 즉 우리가 원하는 어떤 기능들을 모아서 하나의 인터페이스로 선언하는 것이 가장 일반적으로 사용되는 용도이기 때문에 인터페이스는 ‘기능의 묶음’아고 해석하는 것이 편리하다. 상속을 영어로 해석할 때 ‘is a relation'이라고 한다면, 인터페이스는 ’has a relation'으로 해석된다. 즉 어떤 객체가 어떤 인터페이스를 구현했다는 것은 인터페이스에서 정의한 기능들을 그 객체가 모두 구현해두었다는 것을 의미한다. 따라서 실제 객체는 모든 메소드를 구현했겠지만, 인터페이스 자체에는 메소드의 선언만 들어 있게 된다.


(4) 인터페이스는 객체의 타입으로만 사용된다.

인터페이스는 실제 객체로 사용되지는 않지만, 객체의 타입으로는 사용된다. 이 말은 상속에서와 같이 변수 선언 시에 객체의 타입으로 인터페이스를 사용할 수 있다는 것을 의미한다.

--> 인터페이스 a = new 인터페이스 구현 객체( );

이 경우에 컴파일러는 실제로 변수를 사용할 때 변수의 타입만을 보기 때문에 a라는 변수를 이용해서 객체의 메소드를 호출하는 작업을 실행하면 컴파일러는 인터페이스에 호출하려는 메소드가 있는지만을 따지게 된다.

상속에서 타입이 부모 클래스일 때 컴파일러가 부모 클래스에 선언된 메소드만 따지는 것과 같은 방식이라고 생각하자.

인터페이스 역시 객체의 타입으로 선언될 수 있기 때문에 컴파일러는 변수의 타입에 메소드가 존재하는지만 따지게 되고, 실제로 호출되는 것은 실행되고 있는 객체의 메소드가 호출된다.

cf.) implements은 어떤 기준을 구현한다고 보자


4. 인터페이스의 작성

인터페이스를 작성하는 것은 클래스를 작성하는 것과 같다. 다만 키워드로 class대신 interface를 사용한다는 것만 다르다. 그리고 interface에도 클래스와 같이 접근제어자로 public 또는 default를 사용할 수 있다.

interface 인터페이스 이름{ // 인터페이스의 선언

public static final 타입 상수이름 = 값; // 상수 선언부

public abstract 메서드 이름(매개변수 목록); // 추상 메소드 선언부

}


일반적인 클래스의 멤버들과 달리 인터페이스의 멤버들은 다음과 같은 제약사항을 가지고 있다.

- 모든 멤버변수는 public static final 이어야 하며, 이를 생략할 수 있다.

- 모든 메서드는 public abstract 이어야 하며, 이를 생략할 수 있다.

cf.) 인터페이스에 정의된 모든 멤버에 예외없이 적용되는 사항이기 때문에 제어자를 생략할 수 있는 것이며, 편의상 생략하는 경우가 많다. 생략된 제어자는 컴파일 시에 컴파일러가 자동적으로 추가해준다.


interface PlayingCard{

public static final int SPADE =4;

final int DIAMOND = 3; // public static final int DIAMOND = 3;

static int HEART =2; // public static int HEART =2;

int CLOVER =1; // public static int CLOVER =1;

public abstract String getCardNumber();

String getCardKind(); // public abstract String getCardKind();

}


5. 인터페이스의 상속

인터페이스는 인터페이스로부터만 상속받을 수 있으며, 클래스와는 달리 다중상속, 즉 여러 개의 인터페이스로부터 상속을 받는 것이 가능하다.

cf.) 인터페이스는 클래스와는 달리 Object클래스와 같은 최고 조상은 없다.

interface Movable{

void move(int x, int y);// 지정된 위치(x ,y)로 이동하는 기능의 메서드

}

inferface Attackable{

void attack(Unit u);// 지정된 대상(u)을 공격하는 기능의 메서드

}

interface Fightable extends Movable, Attackable{   }

클래스의 상속과 마찬가지로 자손 인터페이스는 조상 인터페이스에 정의된 멤버를 모두 상속받는다. 그래서 Fightable 자체에는 정의된 멤버가 하나도 없지만 조상 인터페이스로 부터 상속받은 두 개의 추상메서드 move(int x, int y)와 attack(Unit u)을 멤버로 갖게된다.


6. 인터페이스의 구현

인터페이스도 추상클래스처럼 그 자체로는 인스턴스를 생성할 수 없으며, 추상클래스가 상속을 통해 추상메서드를 완성하는 것처럼, 인터페이스도 자신에 정의된 추상메서드의 몸통을 만들어주는 클래스를 작성해야하는데, 그 방법은 추상클래스가 자신을 상속받는 클래스를 정의하는 것과 다르지 않다. 다만 클래스는 확장한다는 의미의 키워드 'extends'를 사용하지만 인터페이스는 구현한다는 의미의 키워드 implements'를 사용할 뿐이다.

cf.) 만일 구현하는 인터페이스의 메서드 중 일부만 구현한다면, 추상클래스로 선언되어야 한다.


class FighterTest {

public static void main(String[] args) {

Fighter f = new Fighter();


if (f instanceof Unit) {

System.out.println("f는 Unit클래스의 자손입니다.");

}


if (f instanceof Fightable) {

System.out.println("f는 Fightable인터페이스를 구현했습니다.");

}


if (f instanceof Movable) {

System.out.println("f는 Movable인터페이스를 구현했습니다.");

}


if (f instanceof Attackable) {

System.out.println("f는 Attackable인터페이스를 구현했습니다.");

}


if (f instanceof Object) {

System.out.println("f는 Object클래스의 자손입니다.");

}

}

}


class Fighter extends Unit implements Fightable {

public void move(int x, int y) { /* 내용 생략 */ }

public void attack(Unit u) { /* 내용 생략 */ }

}


class Unit {

int currentHP; // 유닛의 체력

int x; // 유닛의 위치(x좌표)

int y; // 유닛의 위치(y좌표)

}


interface Fightable extends Movable, Attackable { }

interface Movable { void move(int x, int y); }

interface Attackable { void attack(Unit u); }

실행결과)

f는 Unit클래스의 자손입니다.

f는 Fightable인터페이스를 구현했습니다.

f는 Movable인터페이스를 구현했습니다.

f는 Attackable인터페이스를 구현했습니다.

f는 Object클래스의 자손입니다.

인터페이스는 상속 대신 구현이라는 용어를 사용하지만, 인터페이스로부터 상속받은 추상메서드를 구현하는 것이기 때문에 인터페이스도 조금은 다른 의미의 조상이라고 할 수  있다.여기서 주의 깊게 봐두어야 할 것은 movable인터페이스에 정의된 void moveful(int x, int y)를 Fighter클래스에서 구현할 때 접근 제어자를 public으로 했다는 것이다.


7. 인터페이스 관련 주제


(1) 다중 구현은 다중 타입으로 선언할 수 있다.

클래스의 선언에 implements 인터페이스 구문이 나온다는 얘기는 해당 클래스가 인터페이스의 메소드들을 실제로 구현하고 있다는 선언이다.

클래스가 여러 개의 인터페이스를 구현한다는 것은 또 다른 의미로는 하나의 객체를 여러 가지의 타입으로 선언하는 것이 가능하다는 것을 의미한다.

즉 인터페이스도 타입으로 사용된다. ‘MyMp3 mp3 = new TonyMp3( );'에서처럼 어떤 클래스가 인터페이스를 구현하게 되면 변수 선언 시에 인터페이스를 타입으로 사용할 수 있다는 얘기이다. 클래스가 여러 개의 인터페이스를 구현하게 되면 결과적으로 변수의 타입으로도 다양하게 쓰일 수 있다는 것을 의미하게 된다.

ex.) Phone3G phone = new Phone3G( );

      VisualCall v1 = new VisualCall( );

      VoiceCall v2= new VoiceCall( );

--> 변수의 타입으로 보면 실제로 만들어지는 객체는 마찬가지로 Phone3G 이지만 VoiceCall 타입으로도, VisualCall 타입으로도 사용되는 것을 보실 수 있다.


(2) 상속과 인터페이스 차이(다중상속 관련)

상속은 구체적으로 구현된 메소드를 물려주기 때문에 다중 상속을 하게 되면 문제가 생긴다. 하지만, 인터페이스는 스펙(추상 메소드)만을 물려주기 때문에 여러 개의 인터페이스의 같은 메소드를 물려받아도 구현은 실제 구현 클래스 한 곳에서만 한다.

상속과 달리 인터페이스는 하나의 기준이면서 ‘~를 할 수 있는 기능을 가진 객체’의 의미로 해석될 수 있다. 인터페이스 자체가 하나의 클래스가 아니고, 그저 객체를 판단하는 기준이기 때문에 하나의 객체가 여러 가지 기능을 가질 때에는 클래스의 선언 뒤에 여러 개의 인터페이스를 ‘,’를 이용해서 사용할 수 있다.


(3) 인터페이스가 타입으로 쓰일 수 있기에 가능한 일들

인터페이스는 하나의 타입으로 선언되기 때문에 변수의 선언으로 가능한 모든 작업이 고스란히 가능해진다. 우리가 일반적으로 변수를 쓰는 경우는 다음과 같다.

1) 객체를 나중에 다시 사용하기 위해서 변수로 선언하는 경우

cf.) 인터페이스를 변수로 선언하는 경우

인터페이스로 변수를 선언하게 되면 사용하는 입장에서는 보이는 메소드는 인터페이스의 메소드들만 보이게 된다.

인터페이스 변수를 선언하게 되면 뒤에 오는 모든 객체는 간단히 인터페이스만 구현한 객체이면되기 때문에 실제로 new 뒤에 올 수 있는 클래스에 대한 제한이 없게 된다. 따라서 좀 더 시스템이 유연해지는 계기를 마련하게 된다.


2) 메소드의 파라미터나 메소드의 리턴 타입으로 사용하는 경우

메소드의 파라미터나 메소드의 리턴 타입으로 사용되는 경우에는 추상 클래스나 상속을 이용하는 것과 같아진다. 역시 이런 경우에는 상속과는 달리 전혀 무관하지만, 인터페이스에 선언된 기능을 가진 객체이면 되기 때문에 좀 더 확장성 있는 구조가 된다.


3) 배열이나 자료구조를 선언하기 위해서 사용하는 경우

배열이나 자료구조에서 인터페이스 타입으로 선언되는 경우에는 상속의 단점을 보완하는 방식의 설계가 가능해진다. 

--> 인터페이스를 이용하면 이런 작업들이 모두 가능해진다.

- 인터페이스는 전혀 다른 객체를 하나의 타입으로 인식할 수 있게 한다.


cr.)

1) 인터페이스가 실제 객체를 의미하는 것이 아니라 원하는 객체의 스펙을 의미하는 것이다.

2) 어떤 객체가 인터페이스를 구현함에 따라 여러 가지 타입으로 선언될 수 있다는 점이다.

--> 인터페이스 자체가 의미하는 것은 어떤 기능만을 의미하기 때문에 우리가 만든 여러 가지의 클래스에 원하는 인터페이스를 붙여주면 전혀 다른 객체이지만 같은 타입으로 인식할 수 있게 된다.


cp.) 개발하다 예상치 못한 새로운 기능이 추가되는 경우가 있다. 이렇게 전혀 다른 객체들의 공통적인 문제를 해결하는 데 있어서 인터페이스가 도움을 줄 수 있다.

-->  인터페이스는 하나의 타입으로 이전에 전혀 관계가 없는 클래스를 하나의 타입으로 볼 수 있게 한다. 따라서 전혀 엉뚱한 데이터를 가진 객체들을 하나의 자료구조와 같은 타입으로 묶어줄 수 있다.

1) 공통적인 기능만을 인터페이스로 정의해버린다.

가장 먼저 해야 할 일은 공통적인 기능을 인터페이스로 정의하는 것이다. 예를 들어 4가지의 클래스가 결국 매달 지급해야 하는 돈을 계산해주는 기능이 필요하다고 판단된다. 따라서 Ipayable

이라는 인터페이스를 정의하도록 한다.(4가지 클래스가 공통적인 기능을 갖는 인터페이스)

2) 공통 기능을 필요한 클래스가 정의하도록 클래스의 선언을 수정한다.

이제 필요한 클래스가 공통 기능을 할 수 있도록 수정해주어야 한다. 즉 전혀 관계없는 객체들을 공통된 기능을 구현한 객체로 볼 수 있게 한다는 것이다.

3) 인터페이스 타입으로 여러 종류의 객체를 처리할 수 있다.

4가지의 클래스가 동일한 인터페이스를 구현 했다면 전혀 관계가 없는 4가지 클래스의 객체들을 하나의 타입으로 볼 수 있도록 하는 중간 적인 역할이 필요할 때 사용된다.

ex.) IPayable[] arr = new Ipayable( );

    arr[0] = new RegularWorker( );

    arr[1] = new ContractWorker( );

    arr[2] = new PartTimer( );

    arr[3] = new RentalPay( );


(4) 인터페이스는 일종의 접근 제한 역할도 할 수 있다.

예를 들어 실제 MP3가 가진 기능은 playMovie( ), viewImage( ) 기능이지만, 외부에 인터페이스만 호출하게 되면 호출하는 쪽에서는 이 객체를 어떤 타입으로 보는지에 따라서 사용할 수 있는 메소드가 제한되나. 즉, PlayMovie m = new MP3(); 로 보면 실제로 MP3 객체가 가진 기능은 이미지를 보는 기능 viewImage( ) 와 동영상을 보는 기능인 viewImage( )이지만 변수의 선언에 의해서 사용할 수 있는 메소드는 playMovie( ) 만 보이게 된다. 이런 이유 때문에 클래스에 여러 가지 메소드를 만들어 둔 다음 인터페이스로 분리하는 작업을 진행하는 경우가 가끔 있다.

-->  A,B,C라는 인터페이스를 구현한 클래스를 반환할 때 A타입으로 변환하게 되면 외부에서는 A

인터페이스의 메소드만 보이게 된다. 따라서 별도의 접근 제한을 이용하지 않고도 접근 제한과 마찬가지 효과를 보게 하는 방법이다.


- 인터페이스는 다중 상속 문법도 된다.

인터페이스는 다중 구현을 통해서 하나의 객체가 여러 가지의 인터페이스를 구현할 수 있도록 하고 있다.

-->  인터페이스의 다중 상속은 여러 개의 스펙을 모아서 하나의 스펙을 만들어내는 일종의 조합방식이다.

-->  인터페이스의 다중 상속은 ‘스펙+스펙=새로운 스펙’으로 이해하자

만약 각각 한 가지씩의 기능을 가진 인터페이스를 하나의 제품의 스펙으로 규정하길 원할 때 다중상속을 사용한다.


ex.) interface PerfectPhone extends Camera, Mp3, DMB, Widget 

-->  이렇듯 새로운 규격을 만들어 주었다면 이제 PerfectPhone 하나만 물려받으면 끝난다.( 굳이 4가지의 인터페이스를 다 extends할 필요 없다.)


cf.) 인터페이스는 하나의 타입이나 규격일 뿐이지 그 자체가 하나의 객체가 되는 것이 아니다. 따라서 인터페이스의 상속은 클래스의 상속처럼 부모의 속성과 동작을 물려받는 것이 아니다. 인터페이스의 상속은 규격이나 스펙 자체 혹은 기능 자체의 선언을 물려받은 것이다. 규격이나 스펙을 물려받아서 새로운 스펙을 만든다면 기존 여러 개의 스펙을 조합해서 하나로 묶거나 기존의 스펙을 고스란히 물려받은 후에 다시 추가적인 기능을 가지게 하는 것이다.(extends는 상속이 아니다.)


cf.) 인터페이스에서 가장 중요한 사실은 인터페이스를 통해서 객체와 객체 간의 메시지를 주고받는다는 것이다.


(5) 인터페이스는 하나의 클래스에 여러 개를 붙여줄 수 있다.

인터페이스는 객테와 관련된 것이 아니라 객체가 할 수 있는 기능에 대한 정의이기 때문에 상속과는 달리 하나의 객체가 여러 가지의 기능의 스펙을 구현하는 것도 이상한 일이 아니다.

즉 java에서는 단일 상속만을 지원 했던 것과는 달리 하나의 객체는 여러 가지 종류의 기능 스펙인 인터페이스를 구현 할 수 있다.

ex.) 복합기가 프린트도 되고, 팩스도 되고, 복사도 되는 모습(하나의 객체가 여러 개의 기능 스펙을 구현)

복사기 a = new A기계( );

팩스 a = new A기계( );

프린트 a = new A기계( );

-->  하나의 객체를 여러 타입(모습)으로 보는 것이 다형성의 핵심이다.

-->  A 기계(객체)가 여러 가지의 인터페이스를 구현하는 형태이다.

-->  인터페이스 위주로 프로그램을 설계한다는 것은 만들어야 하는 기능에 대한 기준을 미리 잡는다는 것과 유사어 정도라고 생각된다.


'Programing > Java' 카테고리의 다른 글

[Java] 익명클래스  (0) 2014.12.23
[Java] public static void main(String [] args)  (0) 2014.12.23
[Java] 인터페이스와 다형성  (1) 2014.12.21
[Java] 다형성  (0) 2014.12.21
[Java] 쓰레드의 동기화  (0) 2014.12.21

[JavaScript] Text 객체


Text 객체



1. 소개

텍스트 객체는 텍스트 노드에 대한 DOM 객체로 CharcterData를 상속 받는다. 


아래는 텍스트 노드를 찾는 예제다. 주목할 것은 DOM에서는 공백이나 줄바꿈도 텍스트 노드라는 점이다.

<p id="target1">노드없음<span>Hello world</span></p>

<p id="target2">줄바꿈 노드가 숨겨있음

    <span>Hello world</span>

</p>

<script>

var t1 = document.getElementById('target1').firstChild;

var t2 = document.getElementById('target2').firstChild;

 

console.log(t1.firstChild.nodeValue);

try{

    console.log(t2.firstChild.nodeValue);   

} catch(e){

    console.log(e);

}

console.log(t2.nextSibling.firstChild.nodeValue);

</script>

   

-->DOM에서는 공백조차도 분명히 존재하는 객체에 매핑되어 있다.

실행결과)

Hello world

TypeError {stack: (...), message: "Cannot read property 'nodeValue' of null"}

Hello world


2. 주요 기능


(1)  값

텍스트 노드의 값을 가져오는 API

- data

- nodeValue


(2) 조작

- appendData()

- deleteData()

- insertData()

- replaceData()

- subStringData()


(3) 생성

- docuemnt.createTextNode()


3. 값 API

텍스트 노드는 DOM에서 실질적인 데이터가 저장되는 객체이다. 따라서 텍스트 노드에는 값과 관련된 여러 기능들이 있는데 이번 시간에는 값을 가져오는 두개의 API를 알아본다

- nodeValue

- data

<ul>

    <li id="target">html</li> 

    <li>css</li>

    <li>JavaScript</li>

</ul>

<script>

    var t = document.getElementById('target').firstChild;

    console.log(t.nodeValue);

    console.log(t.data);

</script>


t.nodeValue="!!": 텍스트의 문자 값이 '!!'로 바뀐다.


4. 조작 API

텍스트 노드가 상속 받은 CharacterData 객체는 문자를 제어할 수 있는 다양한 API를 제공한다. 아래는 조작과 관련된 API들의 목록이다.

- appendData()

- deleteData()

- insertData()

- replaceData()

- substringData()


<!DOCTYPE html>

<html>

<head>

    <style>

    #target{

        font-size:77px;

        font-family: georgia;

        border-bottom:1px solid black;

        padding-bottom:10px;

    }

    p{

        margin:5px;

    }

    </style>

</head>

<body>

<p id="target">Cording everybody!</p>

<p> data : <input type="text" id="datasource" value="JavaScript" /></p>

<p>   start :<input type="text" id="start" value="5" /></p>

<p> end : <input type="text" id="end" value="5" /></p>

<p><input type="button" value="appendData(data)" onclick="callAppendData()" />

<input type="button" value="deleteData(start,end)" onclick="callDeleteData()" />

<input type="button" value="insertData(start,data)" onclick="callInsertData()" />

<input type="button" value="replaceData(start,end,data)" onclick="callReplaceData()" />

<input type="button" value="substringData(start,end)" onclick="callSubstringData()" /></p>

<script>

    var target = document.getElementById('target').firstChild;

    var data = document.getElementById('datasource');

    var start = document.getElementById('start');

    var end = document.getElementById('end');

    function callAppendData(){

        target.appendData(data.value);

    }

    function callDeleteData(){

        target.deleteData(start.value, end.value);

    }

    function callInsertData(){

        target.insertData(start.value, data.value); 

    }

    function callReplaceData(){

        target.replaceData(start.value, end.value, data.value);

    }

    function callSubstringData(){

        alert(target.substringData(start.value, end.value));

    }

</script>

</body>

</html>

'WebFont-end > JavaScript' 카테고리의 다른 글

[JavaScript] 이벤트 등록방법  (0) 2014.12.25
[JavaScript] 이벤트  (0) 2014.12.25
[JavaScript] Document 객체  (0) 2014.12.23
[JavaScript] Node 객체  (1) 2014.12.23
[JavaScript] Element 객체  (0) 2014.12.22

[JavaScript] Document 객체


Document 객체


1. 소개

Document 객체는 DOM의 스팩이고 이것이 웹브라우저에서는 HTMLDocument 객체로 사용된다. HTMLDocument 객체는 문서 전체를 대표하는 객체라고 할 수 있다. 아래 코드는 이를 보여준다.

<script>

//document 객체는 window 객체의 소속이다.

console.log(window.document);

//document 객체의 자식으로는 Doctype과 html이 있다. 

console.log(window.document.childNodes[0]);

console.log(window.document.childNodes[1]);

</script>


2. 노드 생성 API

document  객체의 주요 임무는 새로운 노드를 생성해주는 역할이다. 이에 대한 내용은 노드 변경 API에서 학습했기 때문에 여기서는 언급하지 않는다.

- createElement()

- createTextNode()


3. 문서 정보 API

- title

- URL

- referrer

- lastModified



'WebFont-end > JavaScript' 카테고리의 다른 글

[JavaScript] 이벤트  (0) 2014.12.25
[JavaScript] Text 객체  (0) 2014.12.23
[JavaScript] Node 객체  (1) 2014.12.23
[JavaScript] Element 객체  (0) 2014.12.22
[JavaScript] HTMLCollection 객체  (0) 2014.12.22