Java에서 Interface를 사용하여 Callback 구현하기

2012/09/19 11:53

프로그래밍에서 꽤 유용한 기능들이 있는데 그중에서 하나가 바로 Callback 이라는 것이다. Callback은 Windows 개발자라면 익히들 알고 있지만 Java 개발자라면 어쩌면 낯선 단어일수도 있다. 하지만 Java 개발자들에게 Listner와 비슷한거라고 하면 대략적인 Callback의 의미를 상상할 수 있을거라 예상된다. 보통 Callback과 Listener는 어떠한 일을 처리하기 위해서 프로세스가 진행하는 도중에 다른 이벤트 처리에 사용하기 때문이다. 하지만 은밀히 말하면 이 두가지는 디자인 패턴(Pattern)이 다르다. Callback은 Command Pattern을 따르고 있고 Listener는 Observer Pattern을 따르고 있기 때문이다. 이 두가지의 차이점은 나중에 다른 포스팅에서 Listener를 설명하면서 다시 한번 자세히 언급하겠다.


일반적으로 프로그래밍에서 Callback 이라는 용어를 다음과 같이 이야기 한다.


호출자(Caller)가 피호출자(Callee)를 호출하는 것이 아니라 피호출자(Callee)가 호출자(Caller)를 호출하는 것을 말한다. 

(참조 http://cafe.naver.com/devctrl.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=1727) 


위키에서는 다음과 같이 정의하고 있다.

프로그래밍에서 콜백(callback)은 다른 코드의 인수로서 넘겨받는 서브루틴이다. 이를 통해 높은 수준의 층에 정의된 서브루틴(또는 함수)을 낮은 수준의 추상화층이 호출할 수 있게 된다. 일반적으로 먼저 높은 수준의 코드가 낮은 수준의 코드에 있는 함수를 호출할 때, 다른 함수의 포인터나 핸들을 넘겨준다. 낮은 수준의 함수를 실행하는 동안에 그 넘겨받은 함수를 적당히 회수, 호출하고, 부분 작업을 실행하는 경우도 있다. 다른 방식으로는 낮은 수준의 함수는 넘겨받은 함수를 '핸들러'로서 등록하고, 낮은 수준의 층에서 비동기적으로(어떠한 반응의 일부로서) 다음에 호출하는데 사용한다. 콜백은 폴리모피즘과 제네릭프로그래밍의 단순화된 대체 수법이며, 어떤 함수의 정확한 동작은 그 낮은 수준의 함수에 넘겨주는 함수 포인터(핸들러)에 의해 바뀐다. 이것은 코드 재사용을 하는 매우 강력한 기법이라고 말할 수 있다.

(참조 http://ko.wikipedia.org/wiki/콜백)


위의 정의에서 보듯 callback은 포인터나 핸들러를 넘겨줘서 피호출자(Callee)가 호출자(Caller)를 호출하는 기법으로 코드 재상용이 가능하고, 비동기적으로 처리할 수 있으며 함수를 추상화 할 수 있기 때문에 UI나 비동기 처리 시스템에서 callback 기법을 많이 사용한다. 


그럼 뜬금 없이 갑자기 왜 Java에서 Callback을 포스팅하는가 하면 바로 Android 앱을 개발할 때 Fragment를 테스트하기 위한 샘플 코드를 만들게 되면 Activity와 Fragment가 바로 Callback을 사용하고 있기 때문이다. 아래는 이클립스에서 Fragment를 이용한 예제를 샘플로 만들면 만들어지는 코드이다.


package net.saltfactory.tutorial;


import net.saltfactory.tutorial.dummy.DummyContent;


import android.R;

import android.app.Activity;

import android.os.Bundle;

import android.support.v4.app.ListFragment;

import android.view.View;

import android.widget.ArrayAdapter;

import android.widget.ListView;


public class ItemListFragment extends ListFragment {


    private static final String STATE_ACTIVATED_POSITION = "activated_position";


    private Callbacks mCallbacks = sDummyCallbacks;

    private int mActivatedPosition = ListView.INVALID_POSITION;


    public interface Callbacks {


        public void onItemSelected(String id);

    }


    private static Callbacks sDummyCallbacks = new Callbacks() {

        @Override

        public void onItemSelected(String id) {

        }

    };


    public ItemListFragment() {

    }


   ... 생략 ...


    @Override

    public void onAttach(Activity activity) {

        super.onAttach(activity);

        if (!(activity instanceof Callbacks)) {

            throw new IllegalStateException("Activity must implement fragment's callbacks.");

        }


        mCallbacks = (Callbacks) activity;

    }


    @Override

    public void onDetach() {

        super.onDetach();

        mCallbacks = sDummyCallbacks;

    }


    @Override

    public void onListItemClick(ListView listView, View view, int position, long id) {

        super.onListItemClick(listView, view, position, id);

        mCallbacks.onItemSelected(DummyContent.ITEMS.get(position).id);

    }


    ... 생략



위 코드를 자세히 살펴보면 Callback을 사용하기 위해서 Java의 Interface를 사용한 것을 확인 할 수 있다. 그렇다. Java에서는 Callback을 사용하기 위해서 interface를 사용한다. 좀더 이해를 돕기 위해서 다음 코드를 살펴보자.


처음으로 살펴볼 것은 Callback을 사용할 수 있는 Interface를 만드는 것이다. 그리고 그 안에는 callbackMethod를 추가한다.

/**

 * filename : CallbackEvent.java

 * 

 */

package net.saltfactory.tutorial;


public interface CallbackEvent {

public void callbackMethod();

}


다음은 Callback을 외부에서 Callback method를 등록할 수 있는 EventRegistration 을 만든다. 이때 생성자에서 Callback으로 구현된 객체를 외부에서 전달 받아서 EventRegistration의 doWork() 메소드에서 외부에서 정의한 callbackMethod를 실행하게 한다.


/**

 * filename : EventRegistration.java

 * 

 */


package net.saltfactory.tutorial;


public class EventRegistration {

private CallbackEvent callbackEvent;

public EventRegistration(CallbackEvent event){

callbackEvent = event;

}

public void doWork(){

callbackEvent.callbackMethod();

}

}



다음은 Main에서 호출자(Caller)와 피호출자(Callee)를 만들어서 콜백을 테스트한다. 아래와 같이 호출자(caller)에 구현된 callbackMethod를 등록해서 피호출자(callee)가 호출자(caller)에 구현된 callbackMethod를 실행할 수 있게 되었다.


/**

 * filename :EventApplication.java

 *  

 */


package net.saltfactory.tutorial;


public class EventApplication {


/**

@param args

*/

public static void main(String[] args) {

// TODO Auto-generated method stub

CallbackEvent callbackEvent = new CallbackEvent(){


@Override

public void callbackMethod() {

// TODO Auto-generated method stub

System.out.println("call callback method from callee");

}

};

EventRegistration eventRegistration = new EventRegistration(callbackEvent);

eventRegistration.doWork();

}


}



이 코드를 실행하면 다음과 같은 결과를 확인 할 수 있다.



이 코드를 유사하게 Android에서는 Activity와 Fragment에 Callback을 사용하고 있는데 이는 Fragment는 반드시 Activity를 가져야하고 Fragment는 Activity의 메소드를 비동기적으로 요청해야하기 때문이다. 이와 같은 상황을 콜백메소드를 이용해서 비동기적인 문제를 해결하고 코드를 재사용할 수 있게 Java의 Interface를 사용해서 Callback을 구현한 것이다. 


<결론>

Callback은 호출자(Caller)에서 구현한 메소드를 피호출자(Callee)가 호출해서 사용할 수 있다. 이렇게 외부에서 메소드를 구현화 시키기 때문에 코드의 재사용성이 높아진다. 그리고 Callback는 피호출자(Callee)가 호출자(Caller)에게 비동기적으로 메세지를 보내어서 데이터처리를 비동기 적으로 처리할 수 있는 장점을 가진다.   자바에서 이러한 Callback 구현은 Java의 Interface의 특징을 이용하여 구현할 수 있다. 


<참고>

1. http://blog.danieldee.com/2009/06/callback-vs-listener.html

2. http://cafe.naver.com/devctrl.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=1727

3. http://ko.wikipedia.org/wiki/콜백

4. http://www.javaworld.com/javatips/jw-javatip10.html



출처 - http://blog.saltfactory.net/191


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

rmi - Hessian Web Service Protocol – Hello World Example  (0) 2013.08.09
java - 이미지 사이즈 변경(image resize)  (0) 2013.06.22
java - listener 만들기  (0) 2013.04.08
java - 파일 전송  (0) 2013.04.04
system.out 출력 포맷  (0) 2013.01.31
Posted by linuxism
,


java listener 만들기!
---- 어떤 Event가 일어나면 그 사건을 주시하는 사람에게 알려주는 것.

callback ..
-어떠 한 클래스내에서 이벤트가 발생하면
  그 클래스를 호출한 녀석에게 그 사실을 알려주는 것.

** 아래의 소스  ** 
인터페이스 Lisntener를  구현한 클래스 A는  클래스 B를 생성한다.
클래스 B가 실행 도중 어떠 한 Event가 일어나면
자기를 생성한 클래스 A에게 알려주고, 
그 처리는 클래스 A 가 한다.!



/* 인터페이스 Listener 
    함수 정의만 하고 구현은 하지 않음
*/ 
Interface Listener
{
    void  Listener();
}

/* 클래스 A는 Listener 를 구현함. */
class A implement Listener
{
          /* 반드시 구현해야 하는 함수 */
          void Listener ()
          {
                   // 어떤 일이 일어났다는 사실을 알았을 때 
                   // 처리 할 일
           }

           public static void main()
           {
                         /* B 객체를 만듬.
                             자기 자신을 Listener 로 등록한다. */
                         B myb  =  new B( this);
         
            }
}





B class 
{
        private : 
               Listener  L;

        B(Listener l)  // 생성자 
        {
                L = l;  // 인자로 받은 listener 를 등록함.
         }   

           이벤트 발생 시 ...
          {
                    /* if Event is occured */
                    // 이벤트가 발생하면 연락 받기 기다리는 Listener L에게 
                   // 사실을 알려 준다...
                   L.Listener ();   
          }
}


아주 대충 ,, 처리되는 방식만 기술. ㅎㅎ



출처 - http://jjakkmi.tistory.com/6





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

java - 이미지 사이즈 변경(image resize)  (0) 2013.06.22
java - listener(callback) 만들기 2  (0) 2013.04.08
java - 파일 전송  (0) 2013.04.04
system.out 출력 포맷  (0) 2013.01.31
java - CRC32 클래스  (0) 2013.01.31
Posted by linuxism
,


SMTP는 텍스트 기반의 프로토콜로서 요구/응답 메시지뿐 아니라 모든 문자가 7bit ASCII로 되어있어야 한다고 규정되어 있다. 이 때문에 문자 표현에 8비트 이상의 코드를 사용하는 언어나 첨부파일과 자주 사용되는 각종 바이너리는 마임(MIME)이라고 불리는 방식으로 7비트로 변환되어 전달된다.

다른글

SMTP는 원래 텍스트 기반 프로토콜이며, 요청 / 응답 메시지뿐 아니라 모든 문자가 7 비트 ASCII 이어야한다는 제한이 있었다. 현재는 확장 기능 8 bit 이상을 요구하는 언어와 첨부 파일에 사용되는 것이 많은 이진 도 그대로 전송하는 것도 가능하지만, 호환성을 고려하면 MIME 하는 방식으로, 7 bit에 맞게 하는 것이 바람직하다.


출처 - http://ko.wikipedia.org/wiki/%EA%B0%84%EC%9D%B4_%EC%9A%B0%ED%8E%B8_%EC%A0%84%EC%86%A1_%ED%94%84%EB%A1%9C%ED%86%A0%EC%BD%9C






php mail 함수

bool mail ( string $to , string $subject , string $message [, string $additional_headers [, string $additional_parameters ]] )


출처 - http://php.net/manual/en/function.mail.php



mail 함수에서  $to , $subject , $message 변수에 한글등 아스키문자 이외의 문자가 있으면 인코딩 해줘야 한다.

예를 들면... 

$subject = "=?UTF-8?B?".base64_encode("메일 제목")."?="; 


그리고 가급적이면 메일제목에는 utf-8말고 euc-kr을 사용하시는 것이 좋을 거 같습니다. 

utf-8을 기본으로 사용하고 있다면 제목만이라도 iconv를 통해 euc-kr로 변환하고 base64로 인코딩해주는게 좋을거 같네요... 


$subject = "=?EUC-KR?B?".base64_encode(iconv("UTF-8","EUC-KR","메일 제목"))."?=";



출처 - http://www.phpschool.com/gnuboard4/bbs/board.php?bo_table=qna_function&wr_id=246037&sca=&sfl=wr_subject%7C%7Cwr_content&stx=mail&sop=and&spt=-82717&page=12








iconv_mime_encode — Composes a MIME header field

reject note Description

string iconv_mime_encode ( string $field_name , string $field_value [, array $preferences = NULL ] )

Composes and returns a string that represents a valid MIME header field, which looks like the following:

Subject: =?ISO-8859-1?Q?Pr=FCfung_f=FCr?= Entwerfen von einer MIME kopfzeile
In the above example, "Subject" is the field name and the portion that begins with "=?ISO-8859-1?..." is the field value.

reject note Parameters

field_name

The field name.

field_value

The field value.

preferences

You can control the behaviour of iconv_mime_encode() by specifying an associative array that contains configuration items to the optional third parameter preferences. The items supported by iconv_mime_encode() are listed below. Note that item names are treated case-sensitive.

Configuration items supported by iconv_mime_encode()
ItemTypeDescriptionDefault valueExample
schemestringSpecifies the method to encode a field value by. The value of this item may be either "B" or "Q", where "B" stands for base64 encoding scheme and "Q" stands for quoted-printableencoding scheme.BB
input-charsetstringSpecifies the character set in which the first parameter field_name and the second parameter field_value are presented. If not given, iconv_mime_encode() assumes those parameters are presented to it in the iconv.internal_encoding ini setting.iconv.internal_encodingISO-8859-1
output-charsetstringSpecifies the character set to use to compose the MIME header.iconv.internal_encodingUTF-8
line-lengthintegerSpecifies the maximum length of the header lines. The resulting header is "folded" to a set of multiple lines in case the resulting header field would be longer than the value of this parameter, according to » RFC2822 - Internet Message Format. If not given, the length will be limited to 76 characters.76996
line-break-charsstringSpecifies the sequence of characters to append to each line as an end-of-line sign when "folding" is performed on a long header field. If not given, this defaults to "\r\n" (CR LF). Note that this parameter is always treated as an ASCII string regardless of the value of input-charset.\r\n\n

reject note Return Values

Returns an encoded MIME field on success, or FALSE if an error occurs during the encoding.

reject note Examples

Example #1 iconv_mime_encode() example

<?php
$preferences 
= array(
    
"input-charset" => "ISO-8859-1",
    
"output-charset" => "UTF-8",
    
"line-length" => 76,
    
"line-break-chars" => "\n"
);
$preferences["scheme"] = "Q";
// This yields "Subject: =?UTF-8?Q?Pr=C3=BCfung=20Pr=C3=BCfung?="
echo iconv_mime_encode("Subject""Prüfung Prüfung"$preferences);

$preferences["scheme"] = "B";
// This yields "Subject: =?UTF-8?B?UHLDvGZ1bmcgUHLDvGZ1bmc=?="
echo iconv_mime_encode("Subject""Prüfung Prüfung"$preferences);
?>

reject note See Also



출처 - http://php.net/manual/en/function.iconv-mime-encode.php











'Development > PHP' 카테고리의 다른 글

php - syslog  (0) 2013.05.15
php - PDT 설치  (0) 2013.05.13
php - 점(.) 연산자  (3) 2013.04.06
php - mail  (0) 2013.04.06
copyright 년도 자동표기하기  (0) 2013.03.06
Posted by linuxism
,