클래스와 객체 핵심정리

  • 모든 자바 코드는 클래스 내에서 정의된다.
  • 클래스는 해당 클래스 유형의 객체를 만드는 방법을 설명하는 역항르 한다. 클래스는 청사진과 같다.
    객체는 각자 알아서 자기 할 일을 처리할 수 있다. 사용자는 객체에서 작업을 처리하는 방법에 대해서는 신경쓰지 않아도 된다.
  • 객체에는 알고 있는 것할 수 있는 것이 있다.
  • 객체가 자기 자신에 대해 알고 있는 것은 인스턴스 변수라고 부른다. 객체의 상태를 나타낸다.
  • 객체가 할 수 있는 것은 메소드라고 부른다. 객체의 행동을 나타낸다.
  • 클래스를 새로 만들 때는 그 클래스 유형의 객체를 만들어서 테스트하는 테스트용 클래스를 따로 만드는 것도 좋다.
  • 클래스에서는 덜 구체적인 상위클래스로부터 인스턴스 변수와 메소드를 상속 할 수 있다.
Posted by 서오석
,
원시 변수와 레퍼런스

가비지 컬렉션 기능이 있는 힙에서의 삶

Book b = new Book();
Book c = new Book();
사용자 삽입 이미지
Book 객체 두 개는 Heap에서 살게 되었다.

레퍼런스: 2개
객체: 2개
-----------------------------------------------------------------------------------------
Book d = c; 이러면
사용자 삽입 이미지




















c와 d는 똑같은 객체를 참조한다.

레퍼런스: 3개
객체: 2개
-----------------------------------------------------------------------------------------
c = b; 이러면
사용자 삽입 이미지

b와 c는 모두 같은 객체를 참조한다.

레퍼런스: 3개
객체: 2개
-----------------------------------------------------------------------------------------

힙에서의 삶과 죽음

Book b = new Book();
Book c = new Book();
사용자 삽입 이미지

Book 객체 두개가 힙에서 살게 되었다.

활성 레퍼런스: 2개
접근할 수 있는 객체: 2개

-----------------------------------------------------------------------------------------

b= c; 이러면
사용자 삽입 이미지

b와 c는 모두 같은 객체를 참조한다. 1번 객체는 버림받았기 때문에 GC의 대상이 된다.

활성 레퍼런스: 2개
접근할 수 있는 객체: 1개
버림받은 객체: 1개

1번 객체는 아무 레퍼런스도 남아있지 않아서 접근도 할 수 없다.
-----------------------------------------------------------------------------------------

c= null; 이러면
사용자 삽입 이미지

2번 객체에는 여전히 활성 레퍼런스(b)가 있으며 활성 레퍼런스가 있는 한 GC대상이 되진 않는다.

활성 레퍼런스: 1개
null 레퍼런스: 1개
접근 할 수 있는 객체: 1개
버림받은 객체: 1개


Posted by 서오석
,

Set 인터페이스

  • HashSet : 데이터를 해쉬 테이블에 담는 클래스로 순서 없이 저장된다.
  • TreeSet : red-black 트리에 저장되며 값에 따라 순서가 정해진다. HashSet보다 느리지만 데이터를 담는 동시에 정렬할 때 유용하다.
  • LinkedHashSet : 해쉬 테이블에 데이터를 담는데 저장된 순서에 따라 순서가 결정된다.

데이터 속도는 비슷하지만 데이터를 꺼낼 때 속도는 TreeSet이 가장 느리고 LinkedHashSet이 가장 빠르다.

List 인터페이스

  • Vector : 크기를 객체 생성시에 지정할 필요가 없는 배열 클래스다.
  • ArraryList : Vector와 비슷하지만, 동기화 처리가 되어 있지 않다.
  • LinkedList : ArrayList와 같지만 Queue 인터페이스를 구현했기 때문에 FIFO 큐 작업을 한다.

Vector가  가장 빠르며 나머지 두개는 비슷하다.

Map 인터페이스

  • HashMap : 데이터를 Hash Table에 담는 클래스다. Hashtable과 다른 점은  NULL값을 허용한다는 것과 동기화가 되어있지 않다는 것이다.
  • Hashtable : 데이터를 Hash Table에 담는 클래스다. 내부에서 관리하는 해쉬 테이블 객체가 동기화되어 있으므로 동기화가 필요한 부분에서는 이 클래스를 사용하기 바란다.
  • TreeMap : red-black 트리에 데이터를 담는다. TreeSet과 다른 점은 키에 순서가 정해진다는 것이다.
  • LinkedHashMap : HashMap과 거의 동일하며 Double Linked List 방식을 사용하여 데이터를 담는다는 점만 다르다.

TreeMap 클래스가 가장 느리며 나머지 3개는 비슷한 속도를 보인다.


속도를 관련해서 왠만해선 속도 차이가 별로 없다.

Posted by 서오석
,

만약 자신이 만든 메서드나 클래스의 수행속도를 알고 싶다면 System.nanoTime을 이용해서 속도를 체크할 수 있다. 물론 프로파일링 툴을 써도 되지만 그냥 코드만으로 단순하게 사용하고 싶은 경우 시간측정용 메서드를 만들 수 있다.


코드는 아래와 같다.

public class StopWatch {
 long startTime;
 long elapsedTime=0;
 StringBuffer currentName;
 boolean threadFlag = false;
 
 public StopWatch(boolean threadFlag){
 currentName = new StringBuffer();
 startTime = System.nanoTime();
 }
 
 public StopWatch(String message){
  changeMessage("",true,true);
 }
 
 public StopWatch(String message, boolean threadFlag){
  changeMessage(message, false, true);
 }
 
 public void changeMessage(String message, boolean threadFlag, boolean resetFlag){
  StringBuffer threadName= new StringBuffer();
  this.threadFlag = threadFlag;
  if(threadFlag){
   threadName.append("ThreadName=").append(Thread.currentThread().getName());  
  }
  currentName.append("[").append(message).append(threadName).append("]");
  if(resetFlag){
   start();
  }
 }
 
 public void start(){
  startTime = System.nanoTime();
  elapsedTime = 0;
 }
 
 public void stop(){
  elapsedTime = System.nanoTime() - startTime;  
 }
 
 public double getElapsedMS(){
  if(elapsedTime ==0)
   stop();
  return elapsedTime/100000.0;
 }
 
 public double getElapsedNano(){
  if(elapsedTime ==0)
   stop();
  return elapsedTime;
 }
 
 public String toString(){
  if(elapsedTime ==0)
   stop();
  currentName.append("elapsed Time: ").append(elapsedTime/1000000.0).append("ms");
  return currentName.toString();
 }
}

Posted by 서오석
,

Core J2EE Pattern Catalog

Core J2EE Patterns - Business Delegate

Context

멀티 티어, 분산된 시스템은 티어들 사이에 데이터를 보내고 받기 위한 RMI(remote method invocations)가 필요하다. 클라이언트들은 분산된 컴포넌트들을 다루어야 하는 복잡성에 노출되어 있다.

Problem

프리젠테이션-티어 컴포넌트들은 비지니스 서비스들과 직접적으로 상호 작용한다. 이런 직접적인 상호 작용은 프리젠테이션 티어에 대한 비지니스 서비스 API(application program interface)의 기본적인 구현 상세사항들을 외부에 노출한다. 결과적으로, 프리젠테이션-티어 컴포넌트들은 비지니스 서비스들의 구현을 바꾸는것에 취약하다: 비지니스 서비스의 구현이 바뀌면 프리젠테이션 티어에서 외부에 노출된 구현 코드또한 바뀌어야 한다.

또한, 그것들은 네트웍 성능상 불리한 요소가 될 것이다. 비지니스 서비스 API를 사용하는 프리젠테이션-티어 컴포넌트들이 네트웍 상에 너무많은 호출을 만들기 때문이다. 이것은 프리젠테이션-티어 컴포넌트들이 클라이언트 쪽의 캐쉬 메카니즘 또는 서비스를 모으는일 없이 기본적인 API를 직접적으로 사용할때 발생한다.

마지막으로, 서비스 API들을 직접적으로 외부에 노출하는 것은 EJB(Enterprise JavaBeans) 기술의 분산된 특성들에 대한 네트웍관련 문제점을 클라이언트가 다루게 한다.


Forces
● 프리젠테이션-티어 클라이언트들이 비지니스 서비스에 접근해야 한다.

● 다양한 클라이언트들(디바이스들, 웹 클라이언트들, thick 클라이언트들)이 비지니스 서비스에 접근해야 한다.
● 비지니스 서비스 API들은 비지니스 요구사항들의 변화에 따라 바뀔수 있다.
● 프리젠테이션-티어 클라이언트들과 비지니스 서비스들 간의 결합을 최소화 시키는것이 바람직하다.

    그러므로, lookup과 access과 같은 서비스들의 기본적인 구현 상세 사항들을 숨긴다.
● 클라이언트들은 비지니스 서비스 정보를 위한 캐쉬 메카니즘을 구현해야 할 필요성이 있을 수 있다.
● 클라이언트과 비지니스 서비스들 간의 네트웍 트래픽을 줄이는 것이 바람직 하다.


※ thick 클라이언트
Thick 클라이언트는 Rich 클라이언트라고 지칭 되기도 한다. Thick 클라이언트의 대표적인 예 가 될 수 있는 환경으로는 금융권 사이트들을 들 수 있다. 키보드의 후킹(키보드로 보낸 메시지를 가로채는 작업)과 같은 작업을 보안하기 위해서는 클라이언트는 반드시 보안 모듈을 포함해야만 한다. 모듈을 배포하는 예로서는 ActiveX가 될 수가 있다. 하지만 ActiveX는 보안의 문제와 배포, 생산성 저하라는 단점들을 가지고 있다. 이와 반대로 Thin 클라이언트는 순수한 웹사이트를 그려보면 될 것이다. Thin 클라이언트는 배포가 쉽고, 유지할 수 있는 장점이 있는 반면에 사용자를 100% 만족시키지 못한다. 즉, 브라우저 기술의 한계가 나타나게 되는 것이다.


Solution(해결방안)
프리젠테이션-티어 클라이언트들과 비지니스 서비스들 간의 결합을 줄이기 위해 Business Delegate를 사용하라. Business Delegate는 EJB 기술의 lookup과 access와 같은 비지니스 서비스의 기본적인 구현 상세 사항들을 숨긴다.

Business Delegate는 클라이언트-측 비지니스 abstraction 처럼 동작한다; 이것은 비지니스 서비스들의 구현을 위한 abstraction을 제공하며 서비스들을 숨긴다. Business Delegate를 사용하면 프리젠테이션-티어 클라이언트들과 시스템의 비지니스 서비스들간의 결합을 줄인다. 구현 전략에 따라 Business Delegate는 비지니스 서비스 API의 구현안에서 발생 할 수 있는 휘발성(※서비스가 없어지는경우?)으로 부터 클라이언트들을 보호한다. 잠재적으로 이것은 비지니스 서비스 API 또는 이것의 기본적인 구현이 변할때 프리젠테이션-티어 클라이언트 코드가 수정되어야 하는 수를 감소시킨다.

그럼에도 불구하고, 기본적인 비지니스 서비스 API가 바뀌면 Business Delegate 안의 인터페이스 함수들은 여전히 수정을 필요로 할 수도 있다. 그렇지만, Business Delegate 보다 비지니스 서비스가 바뀌는 경우가 더 일반적인 경우일 것이다.

때때로, 개발자들은 비지니스 레이어를 추상화 하는것과 같은 미래에 이익이 될만한 디자인 목표가 추가적인 선행 작업을 야기시키는 것에 대해 회의적이다.

그럼에도 불구하고, 이 패턴 또는 이것의 전략들을 이용하는 것은 작은 양의 추가적인 선행 작업만으로 중요한 이점들을 제공하는 결과를 가져온다.

중요한 이점은 기본적인 서비스의 상세 사항을 숨기는 것이다. 예를 들면, 클라이언트는 naming과 lookup 서비스들에 대해 명쾌해 진다.

또한 Business Delegate는 비지니스 서비스들로 부터의 예외(java.rmi.Remote exceptions, Java Messages Service (JMS) exceptions 등등)를 처리한다.

Business Delegate는 서비스 레벨의 예외들을 중간에 가로채고 대신에 어플리케이션 레벨의 예외들을 생성한다.

어플리케이션 레벨의 예외들은 클라이언트에 의해 처리되기가 더욱 쉽고 사용자에게 친숙 할 것이다.

또한 Business Delegate는 서비스 실패시 발생하는 이벤트에서 필요한 모든 retry 또는 recovery 오퍼레이션들을 해결하지 못 할 문제라고 결정되기 전까지 클라이언트에 문제점을 노출하지 않고 명쾌하게 수행한다. 이런 점들이 패턴을 사용하는 이유이다.

또다른 이점은 delegate가 결과들을 캐쉬 할 수 있고 리모트 비지니스 서비스들을 참조 할 수 있다는 것이다.

캐쉬는 네트웍을 통한 불필요하고 값비싼 왕복들(round trips)을 제한하기 때문에 성능을 매우 많이 향상 시킨다.

Business Delegate는 Lookup 서비스에 의해 호출되는 컴포넌트를 이용한다.

Lookup 서비스는 비지니스 서비스 lookup 코드의 기본적 상세 구현을 숨길 책임이 있다.

Lookup Service는 Delegate의 일부분으로 작성될 수 있지만 우리는 Service Locator 패턴이 적용된 분리된 컴포넌트로 구현되기를 추천한다. (368 페이지의 "Service Locator" 참조.)

Business Delegate가 Session Facade와 함께 사용될때 일반적으로 둘 사이에 one-to-one 관계가 성립한다.

이런 one-to-one 관계는 여러개의 비지니스 서비스들과 상호작용 하는것(one-to-many 관계를 생성하는것)과 관련된 Business Delegate안에 캡슐화 되어져 있을 수 있는 로직이 때때로 Session Facade를 하나의 요인으로 다시 포함되기 때문에 존재한다.

마지막으로, 이 패턴이 간단히 프리젠테이션과 비지니스 티어들이 아니라, 다른 티어들간의 결합을 줄이는데 사용될수 있다는 것이 주목받을 만한 것이다.


Structure(구조)

Figure 8.1은 Business Delegate 패턴을 표현하는 클래스 다이어그램을 보여준다. 클라이언트는 기본적인 비지니스 서비스에의 접근을 제공하기 위해 BusinessDelegate를 요청한다. BusinessDelegate는 요청된 BusinessService 컴포넌트를 얻기 위해 LookupService를 이용한다.

사용자 삽입 이미지

Figure 8.1 BusinessDelegate class diagram



Participants and Responsibilities


Figure 8.2 와 Figure 8.3 은 Business Delegate 패턴의 일반적인 상호작용을 설명하는 시퀀스 다이어그램을 보여준다.

사용자 삽입 이미지


Figure 8.2 BusinessDelegate sequence diagram


BusinessDelegate는 business service를 얻기위해 LookupService를 이용한다. business service는 클라이언트 관점에서 보면 비지니스 함수들을 호출하기 위해 사용된다. Get ID 함수는 BusinessDelegate가 비지니스 서비스를 위한 handle(예, EJBHandle 객체)의 String 버젼을 얻은다음 클라이언트에 String으로 리턴 할 수 있다는 것을 보여준다. 클라이언트는 나중에 비지니스 서비스에 다시 연결하기 위해 handle을 얻었을때 사용된 handle의 String 버젼을 이용할 수 있다. 이 기술은 새로운 lookup들을 피하려고 한다, handle은 이것의 비지니스 인스턴스에 다시 접속할 수 있는 능력이 있기 때문이다.

handle 객체들이 컨테이너 제공자에 의해 구현되었으며 다른 벤더들이 만든 컨테이너들 에서는 사용할 수 없다는 것을 주의하라.


Figure 8.3 의 시퀀스 다이어그램은 handle을 이용해 BusinessService(예, session 또는 entity bean)를 얻는 것을 보여준다.

사용자 삽입 이미지

Figure 8.3 BusinessDelegate with ID sequence diagram



BusinessDelegate


BusinessDelegate의 역활은 business service의 제어와 보호이다. BusinessDelegate는 클라이언트에 2가지 타입으로 노출될 수 있다. 첫번째 요청 타입은 ID없이 BusinessDelegate를 설명한다, 반면 다른 하나는 ID를 가지고 설명한다, ID는 EJBHome 또는 EJBObject와 같은 remote object 참조의 String version 이다.


ID없이 초기화 할때 BusinessDelegate는 Lookup 서비스로 부터 서비스를 요청한다. 일반적으로 EJBHome 같은 Service Factory를 리턴하는 Service Locator 로서 구현된다. (368 페이지의 "Service Locator" 참조) BusinessDelegate는 Service Factory가 enterprise bean 같은 BusinessService를 얻고, 생성하고, 또는 제거하는 것을 요청한다.


ID string을 가지고 초기화 할때 BusinessDelegate는 BusinessService에 재접속하기 위해  ID string을 사용한다. 그러므로, BusinessDelegate는 BusinessService의 naming과 lookup의 기본적 상세 구현 으로부터 클라이언트를 보호한다. 여기에 더해, 프리젠테이션-티어 클라이언트는 결코 BusinessSession에 원격 호출을 직접적으로 하지 않는다; 대신에, 클라이언트는 BusinessDelegate를 이용한다.


LookupService


BusinessDelegate는 BusinessService를 얻기위해 LookupService를 이용한다. LookupService는 BusinessService lookup의 상세 구현을 갭슐화 한다.


BusinessService


BusinessService는 클라이언트에 요청된 서비스를 제공하는 비지니스-티어 컴포넌트(예, enterprise bean 또는 JMS component) 이다.



Strategies(전략)


Delegate Proxy Strategy


Business Delegate는 business service API의 기본 함수들을 클라이언트가 접근할 수 있게 하기위한 인터페이스를 외부에 노출한다. 이 전략에서, Business Delegate가 클라이언트 함수들을 session bean에 넘기는 proxy 기능을 제공하는 이것은 갭술화 이다. Business Delegate는 추가적으로 필요한 모든 데이터(lookup횟수를 줄여 성능향상을 얻을 수 있는 세션빈의 홈 또는 리모트 객체들의 리모트 참조)를 캐쉬 할 수 있다. Business Delegate는 또한 Service Locator의 서비스들을 이용해 이런 참조들을 String versions (IDs) 바꿀 수 있으며 그 반대도 가능하다.


이 전략을 위한 예제 구현은 이 패턴의 "Sample Code" 섹션에서 논의된다.


Delegate Adapter Strategy


Business Delegate는 Java 2 플랫폼, Enterprise Edition (J2EE) 기반의 서비스와 통신하는 B2B 환경에 매우 적합하다. 다른 종류의 시스템들은 통합 언어로 XML을 사용할 것이다. 어떤 시스템을 다른 시스템에 통합하는 것은 일반적으로 두개의 다른 시스템들을 통합하기 위한 Adapter [GoF] 를 필요로 한다. Figure 8.4 에서 예제를 볼수 있다.

사용자 삽입 이미지


Figure 8.4 Using the Business Delegate pattern with an Adapter strategy



Consequences (결론)


Reduces Coupling, Improves Manageability (결합을 줄이고, 관리성을 향상시킨다)
Business Delegate는 비지니스-티어 상세 구현을 숨김으로서 프리젠테이션 티어과 비지니스 티어간의 결합을 줄인다. 이것은 Business Delegate라는 하나의 공간에 집중화 시킴으로서 변화를 관리하기 더 쉽다.


Translates Business Service Exceptions (비지니스 서비스 예외들을 변환한다)
Business Delegate는 network 또는 infrastructure-related 예외들을 비지니스 예외들로 변환하고 기본적인 구현 명세서의 정보로 부터 클라이언트들을 보호하는데 적합하다.


Implements Failure Recovery and Thread Synchronization (실패 복구와 스레드 동기화를 구현한다)
비지니스 서비스 실패가 발생하면 Business Delegate는 클라이언트에 문제를 노출하지 않고 자동 복구 기능을 실행할 수 있다. 복구가 성공적으로 이루어 지면 크라이언트는 이 실패에 대해 알 필요가 없다. 만약 복구시도가 성공적이지 못하면 Business Delegate는 실패에 대해 클라이언트에 알릴 필요가 있다. 추가적으로, 만약 필요하면 비지니스 delegate 함수들은 동기화(synchronized) 될수 있다.


Exposes Simpler, Uniform Interface to Business Tier (비지니스 티어에 간결하고 일관된 인터페이스를 노출한다)
클라이언트에 더 나은 서비스를 하기위해 Business Delegate는 기본적인 엔터프라이즈 빈들에 의해 제공되는 다양한 인터페이스를 제공 할수도 있다.


Impacts Performance (성능 효과)
Business Delegate는 공통적인 서비스 요청들을 위해 프리젠테이션 티어에 캐쉬 서비스(그리고 더 좋은 성능)를 제공할 수 있다.


Introduces Additional Layer (추가적인 레이어 삽입)
Business Delegate는 클라이언트와 서비스 사이의 불필요한 레이어의 추가로 인해 추가적인 복잡성이 추가되고 유연성을 줄이는 것으로 보여질 수 있다. 어떤 개발자들은 Delegate Proxy 전략을 이용한 구현들을 가지고 Business Delegates를 개발하는 것은 불필요한 노력을 들이는 것으로 느낄수 있다. 그렇지만, 일반적으로 그런 약점들 보다  패턴이 주는 잇점들이 더 중요하다.


Hides Remoteness (원격특성들을 숨긴다)
location의 명쾌함이 이 패턴이 주는 잇점중 하나인 반면, 개발자가 로컬에 있는 remote service를 다루기 때문에 다양한 문제점이 발생 할 수 있다. 만약 클라이언트 개발자가 Business Delegate는 remote service의 클라이언트 측 프록시라는 것을 이해하지 못하면 이런 문제점이 발생할 수 있다. 일반적으로, Business Delegate에 있는 함수 호출은 내부에 있는 원격 함수 호출의 결과를 가져온다. 이것을 무시하고 개발자가 단일 업무를 수행하기 위해 많은 양의 함수 호출을 만들려고 시도한다면 네트웍 트래픽을 증가시킬 것이다.



Sample Code (예제 코드)


Implementing the Business Delegate Pattern (Business Delegate 패턴 구현)


Professional Services Application (PSA) 를 고려하는 웹-티어 클라이언트는 Session Facade 패턴을 구현하는 세션빈에 접근하기를 필요로한다. Business Delegate 패턴은 ResourceDelegate(Delegate class)를 디자인하기 위해 적용될 수 있다. ResourceDelegate는 ResourceSession(session bean)을 다루를 복잡성을 갭슐화 한다. ResourceDelegate는 Example 8.1 에서 보여지는 이 예제를 구현한다. 그리고 상응하는 원격 인터페이스인 ResourceSession(Session Facade bean)은 Example 8.2 에서 볼수 있다.


Example 8.1 Implementing Business Delegate Pattern - ResourceDelegate

------------------------------------------------------------------------------------------------

// imports
...

public class ResourceDelegate {

  // Remote reference for Session Facade
  private ResourceSession session;

  // Class for Session Facade's Home object
  private static final Class homeClazz =
  corepatterns.apps.psa.ejb.ResourceSessionHome.class;

  // Default Constructor. Looks up home and connects
  // to session by creating a new one
  public ResourceDelegate() throws ResourceException {
    try {
      ResourceSessionHome home = (ResourceSessionHome)
        ServiceLocator.getInstance().getHome(
          "Resource", homeClazz);
      session = home.create();
    } catch(ServiceLocatorException ex) {
      // Translate Service Locator exception into
      // application exception
      throw new ResourceException(...);
    } catch(CreateException ex) {
      // Translate the Session create exception into
      // application exception
      throw new ResourceException(...);
    } catch(RemoteException ex) {
      // Translate the Remote exception into
      // application exception
      throw new ResourceException(...);
    }
  }

  // Constructor that accepts an ID (Handle id) and
  // reconnects to the prior session bean instead
  // of creating a new one
  public BusinessDelegate(String id)
    throws ResourceException {
    super();
    reconnect(id);
  }

  // Returns a String ID the client can use at a
  // later time to reconnect to the session bean
  public String getID() {
    try {
      return ServiceLocator.getId(session);
    } catch (Exception e) {
      // Throw an application exception
    }
 }

  // method to reconnect using String ID
  public void reconnect(String id)
    throws ResourceException {
    try {
      session = (ResourceSession)
                ServiceLocator.getService(id);
    } catch (RemoteException ex) {
      // Translate the Remote exception into
      // application exception
      throw new ResourceException(...);
    }
  }

  // The following are the business methods
  // proxied to the Session Facade. If any service
  // exception is encountered, these methods convert
  // them into application exceptions such as
  // ResourceException, SkillSetException, and so
  // forth.

  public ResourceTO setCurrentResource(
    String resourceId)
    throws ResourceException {
    try {
      return session.setCurrentResource(resourceId);
    } catch (RemoteException ex) {
      // Translate the service exception into
      // application exception
      throw new ResourceException(...);
    }
  }

  public ResourceTO getResourceDetails()
    throws ResourceException {

    try {
      return session.getResourceDetails();
    } catch(RemoteException ex) {
      // Translate the service exception into
      // application exception
      throw new ResourceException(...);
    }
  }

  public void setResourceDetails(ResourceTO vo)
    throws ResourceException {
    try {
      session.setResourceDetails(vo);
    } catch(RemoteException ex) {
      throw new ResourceException(...);
    }
  }

  public void addNewResource(ResourceTO vo)
    throws ResourceException {
    try {
      session.addResource(vo);
    } catch(RemoteException ex) {
      throw new ResourceException(...);
    }
  }

  // all other proxy method to session bean
  ...
}

------------------------------------------------------------------------------------------------


Example 8.2 Remote Interface for ResourceSession

------------------------------------------------------------------------------------------------

// imports
...
public interface ResourceSession extends EJBObject {

  public ResourceTO setCurrentResource(
    String resourceId) throws
    RemoteException, ResourceException;

  public ResourceTO getResourceDetails()
     throws RemoteException, ResourceException;
  public void setResourceDetails(ResourceTO resource)
     throws RemoteException, ResourceException;

  public void addResource(ResourceTO resource)
      throws RemoteException, ResourceException;

  public void removeResource()
      throws RemoteException, ResourceException;

  // methods for managing blockout time by the
  // resource
  public void addBlockoutTime(Collection blockoutTime)
      throws RemoteException, BlockoutTimeException;

  public void updateBlockoutTime(
    Collection blockoutTime)
      throws RemoteException, BlockoutTimeException;

  public void removeBlockoutTime(
    Collection blockoutTime)
      throws RemoteException, BlockoutTimeException;

  public void removeAllBlockoutTime()
      throws RemoteException, BlockoutTimeException;

  // methods for resource skillsets time by the
  //resource
  public void addSkillSets(Collection skillSet)
      throws RemoteException, SkillSetException;

  public void updateSkillSets(Collection skillSet)
      throws RemoteException, SkillSetException;

  public void removeSkillSet(Collection skillSet)
      throws RemoteException, SkillSetException;

  ...
}

------------------------------------------------------------------------------------------------


 

Related Patterns (관련 패턴)


● Service Locator
Service Locator 패턴은 Business Delegate의 Service Locator를 생성하고 모든 비지니스 서비스의 lookup과 access 코드의 상세 구현을 숨기는데 사용될 수 있다.


● Proxy [GoF]
Business Delegate는 프락시 처럼 동작하고 비지니스 티어안의 객체들을 위해 대리인 역활(stand-in)을 제공 할 수 있다.


● Adapter [GoF]
Business Delegate는 서로다른 시스템들을 위한 결합을 제공하는 Adapter 패턴을 사용 할 수 있다.


● Broker [POSA1]
Business Delegate는 다른 티어들안의 클라이언트들로 부터 비지니스 티어 객체들을 분리하는 broker 역활을 수행한다.

원본 : http://java.sun.com/blueprints/corej2eepatterns/Patterns/BusinessDelegate.html

번역 : 김운주 ounju@naver.com

'개발 이야기 > Java Story' 카테고리의 다른 글

JVM GC와 메모리 튜닝 (조대협)  (0) 2010.02.11
Java jstat로 메모리 모니터링  (0) 2010.02.11
iBatis 튜토리얼 문서  (0) 2008.05.15
Web Service 이야기  (0) 2008.05.08
Xpath Syntax  (0) 2008.05.03
Posted by 서오석
,

Creative Commons License



일반적으로 String 객체를 가지고 조작하는 일들이 빈번하게 일어나는데 가장 흔하게 볼 수 있는 사례가 다음과 같다.

String name = "아무개";
System.out.println("안녕하세요, 저는 " + name + "입니다");


이 예에서는 3 개의 String 객체들이 사용되고 있다.

  • "아무개"
  • "안녕하세요, 저는 "
  • "입니다"

이 세 개의 String 객체들이 + 연산자에 의해 더해지고 그 결과를 System.out.println()으로 전달한다.

문제는 String 클래스가 불변 클래스라는 데에 있다. 불변 클래스란 내부 속성이 변하지 않는 클래스를 말한다. 따라서 String 객체에 대한 + 연산자는 첫 번째 String 객체에 다음 String 객체를 더하는 것이 아니라 둘을 포함하는 새로운 String 객체를 생성한다. 위의 예가 처리되는 과정을 자세히 살펴보면 다음과 같다.

  1. String 객체0 "아무개"를 String 변수 name에 설정한다.
  2. String 객체1 "안녕하세요, 저는 "을 생성한다.
  3. String 객체2 "입니다"를 생성한다.
  4. 객체1과 객체0를 이용하여 String 객체3 "안녕하세요, 저는 아무개"를 생성한다.
  5. 객체3과 객체2를 이용하여 String 객체4 "안녕하세요, 저는 아무개입니다"를 생성한다.
  6. 객체4를 System.out.println()으로 전달한다.

알게 모르게 객체3과 객체4라는 낭비가 발생한다. 사실 이 예에서는 그리 심각한 문제가 아니지만 String에 대한 + 연산이 매우 빈번하게 일어나면 티끌 모아 태산이라고 퍼포먼스 저하를 발생시킬 수 있다. 이는 전적으로 String 클래스가 불변 클래스이기 때문에 발생한다.

이러한 문제 때문에 JDK는 StringBuffer 클래스를 제공한다. StringBuffer 클래스는 불변 클래스가 아니며, append() 를 통해 내부 속성을 변형시킬 수 있다. StringBuffer 클래스를 이용해 수정한 코드는 다음과 같다.

String name = "아무개";
StringBuffer buffer = new StringBuffer();
buffer.append("안녕하세요, 저는 ").append(name).append("입니다");
System.out.println(buffer.toString());


StringBuffer 클래스를 이용하면 위의 예에서 생긴 객체3과 객체4와 같은 낭비를 발생시키지 않는다. toString()을 호출할 때 비로소 최종 결과물을 String 객체로 반환하는 것이 전부일 뿐이다.

StringBuffer 클래스의 모든 메소드는 동기화되어있다. 멀티스레딩 환경에 적응하기 위함인데 두 번째 예에서처럼 멀티스레딩을 고려할 필요가 없는 상황에서라면 동기화는 역시 퍼포먼스 저하를 일으킨다. JDK는 이에 대해 StringBuilder 클래스를 제공한다. StringBuilder 클래스는 StringBuffer 클래스와 API가 동일하며 동기화를 하지 않는다.

String 객체에 대한 + 연산은 사실 개발 과정에서 매우 빈번하게 일어난다. 대부분 로그를 남기는 목적으로 사용하는데 로그를 남기는 행위가 필요 이상으로 퍼포먼스를 갉아먹는 것은 꽤나 바람직하지 못하다. 로그 등의 목적이라면 StringBuilder 클래스를, 동기화가 필요한 곳이라면 StringBuffer 클래스를 사용하라!

Posted by 서오석
,