2012-08-02 4 views
4

WindowItem 클래스에 Java 클래스가 있습니다.이 메소드 중 하나는 스레드로부터 안전하지 않습니다. WindowItem은 외부 프레임 워크의 일부이기 때문에 수정할 수 없습니다. 그래서 나는 그것에 대한 Decorator를 구현하는 것을 알았다. 그것은 문제의 메서드에 "동기화 된"키워드를 가지고있다.최종 메소드가있는 Java 용 Decorator

Decorator는 WindowItem을 확장하며 WindowItem도 포함합니다. 데코레이터 패턴 다음에는 데코레이터에 포함 된 WindowItem을 호출하는 데코레이터에 메서드를 만듭니다.

그러나 WindowItem에는 데코레이터에서 재정의 할 수없는 몇 가지 최종 방법이 있습니다. 이로 인해 Decorator의 투명성이 손상됩니다. 의이 명시 만들어 보자 : 새로운 WindowItemDecorator (아이템) -와 스레드 안전 문제가 사라 : 내 자신의 코드에서

public class WindowItem { 
    private List<WindowItem> windows; 

    public Properties getMethodWithProblem() { 
     ... 
    } 

    public final int getwindowCount() { 
     return windows.size(); 
    } 
} 

public class WindowItemDecorator extends WindowItem { 
    private WindowItem item; 

    public WindowItemDecorator(WindowItem item) { 
     this.item = item; 
    } 

    # Here I solve the problem by adding the synchronized keyword: 
    public synchronized Properties getgetMethodWithProblem() { 
     return super.getMethodWithProblem(); 
    } 

    # Here I should override getWindowCount() but I can't because it's final 
} 

를, 내가 어딘가 WindowItem을 통과해야 할 때마다, 내가 먼저 장식에 싸서. 그러나 내 코드가 WindowItemDecorator에서 getwindowCount()를 호출하면 항상 0이됩니다. "item"멤버 대신 슈퍼 클래스에서 getWindowCount()를 실행합니다.

그래서 나는이 클래스에 대한 장식자를 만드는 것이 불가능하게 만드는 WindowItem (public final 메서드가 있다는 사실)의 디자인을 말합니다.

맞습니까? 아니면 뭔가 빠졌습니까?

이 경우 데코레이터에 창의 목록 복사본을 유지하고 동기화 상태로 유지 한 다음 getWindowCount() 결과가 정확할 수 있습니다. 그러나이 경우 프레임 워크를 포크하고 패치하는 것을 선호합니다 ...

+0

첫 번째 반사가 적합하지만 최종 방법을 사용하면 반사를 무시할 수 없습니다. "WindowItem"유형의 객체를 전달/조작해야합니까? 그렇지 않은 경우 Decorator 패턴을 사용할 필요가 없습니다. 컴포지션을 사용하고 WindowItem의 마지막 메서드에 대한 호출을 제어 할 수 있습니다.이 클래스는 WindowItem을 확장하지 않지만 컴포지션을 통해 인스턴스를 사용하는 새 클래스에 래핑하여 호출 할 수 있습니다. – Ushox

답변

0

질문에 대한 답은 예입니다. 최종 메서드를 재정 의하여 할 수 없으므로이 클래스의 데코레이터를 만들 수 없습니다.

문제가있는 메서드를 재정의하고 메서드를 동기화하여 문제를 해결할 수 있으면 그냥 그대로 두어도됩니다. 즉, 하위 클래스를 사용하고 데코레이터 패턴을 사용하지 말라.

+0

감사합니다. 이것은 WindowItem 객체를 생성하는 경우 좋은 해결책입니다. 그런 다음 WindowItem 객체를 만드는 대신 SyncedWindowItem을 만들어 문제를 해결합니다. 불행히도, WindowItem 객체는 나를 위해 만들어졌습니다. (심지어 추상적 인 클래스조차도 아닙니다.) 그래서 이미 존재하는 객체에 대해서는 할 수 없습니다. – Paul

1

아마도 Delegation Pattern을 사용할 수 있습니다. WindowItem 클래스가 관심있는 모든 메서드를 정의하는 인터페이스를 구현하면 제대로 작동합니다. 또는 WindowItem이 아닌 위임 된 클래스를 참조하기 위해 기존 코드를 너무 많이 손상시키지 않는 경우

+0

문제는 그보다 더 미묘합니다.'WindowItem'을위한'인터페이스 '가없고'WindowItem'을 건네줍니다. – fommil

+0

당신이 말하는 것은 클래스 자체 대신에 WindowItem 인터페이스를위한 데코레이터를 만드는 것이라고 생각합니다. 나는 그것에 동의 할 것이지만이 경우에는 그러한 인터페이스가 없다. – Paul

+0

@Paul 스윙과 미스. 세상에는 인터페이스가 충분하지 않습니다. –

-1

동료가 문제를 해결할 수 있다고 생각했습니다. 목록 창을 수정하는 모든 메소드를 살펴봄으로써 "항목"멤버의 상태와 수퍼 클래스의 상태를 동기화 할 수 있습니다. 몇 가지가 있습니다 : addWindow, removeWindow. 대신 호출하는 그냥 "item.addWindow는 (...)"데코레이터에, 나뿐만 아니라 슈퍼 클래스에 addWindow 전화 :

보통 장식 :

public void addWindow(WindowItem newItem) { 
    item.addWindow(newItem); 
} 

이 경우 내가 할 :

public void addWindow(WindowItem newItem) { 
    super.addWindow(newItem); 
    item.addWindow(newItem); 
} 

상태를 동기화 상태로 유지하고 최종 메소드의 반환 값이 정확합니다.

이것은 장식 된 클래스의 내부 구조에 따라 작동하거나 작동하지 않을 수있는 솔루션입니다.

+0

일반적인 해결책은 아니지만이 경우에는 내부 상태가 동기화되어있는 경우 최종 메소드를 재정의 할 필요가 없기 때문에이 경우 작동합니다 (이 경우!). 마지막 메소드는 getWindowCount()입니다. 수퍼 클래스가 "항목"에 같은 수의 창을 가지고 있는지 확인하면 getWindowCount()를 재정의 할 필요가 없습니다. – Paul

+0

그래서 기본적으로 인스턴스의 복사본 두 개를 보관합니다. 하나는 대리인이고 다른 하나는 수퍼바이저입니다. 따라서 한 메서드에 대한 올바른 대답을 반환하고 다른 모든 메서드에는 올바른 스레드 안전 로직을 추가합니다. ? 그것을 유지하는 것을 즐긴다! :-) – fommil

+0

덧붙여서 [경쟁 조건]에 취약한 두 가지 버전 (http://en.wikipedia.org/wiki/Race_condition)을 사용하여 클래스의 스레드 안전성을 잠재적으로 손상시킬 수 있습니다). 그리고 당신의 컨트롤 밖에는 원래의'WindowItem'에 대한 참조가 없다고 저는 믿습니다. – fommil

1

이런 식으로 문제를 생각하지 않으시겠습니까? WindowItem의 스레드 안전성을 가정하지 않고 코드에서 스레딩 문제를 처리하지 않는 것이 좋습니다.

// I personally prefer ReadWriteLocks, but this sounds like it will do... 
synchronized (windowItem) { 
    windowItem.getMethodWithProblem(); 
} 

그런 다음 스레드 유지 관리를 위해 RFE를 패키지 관리자와 함께 제출하십시오.

실제로 클래스가 스레드 안전성을 갖도록 설계되지 않은 경우 일부 synchronized 키워드가 실제로 문제를 해결할 가능성은 거의 없습니다. 더도있다 - 어떤 누군가가 "스레드 안전"의미가 명시 적으로를 사용하는 대신 List을 사용하여 변형 Correct way to synchronize ArrayList in java "를 준비 스레드"있는 그대로 ;-)

이 (덧붙여, WindowItem 확실히 스레드로부터 안전하지 항상 상대적이다 List이 스레드 안전 방식으로 액세스되고 있음을 보장합니다.

+1

... 그리고 인터페이스를 구현하도록 요청하십시오. 결코 상처를 입히지 않습니다 (특히 단위 테스트에서 조롱하는 경우). –

+0

'interface's가 너무 무거울 경우 적어도 최소한의 'final' 수정자를 제거해야합니다. 또는 적어도 일관성이 있어야합니다. http://stackoverflow.com/questions/218744 – fommil

+0

데코레이터를 사용하여이 문제를 해결하는 요점은 WindowItem의 모든 용도를 수정하지 않고 한 곳에서 문제를 해결한다는 것입니다. 내 코드. – Paul

관련 문제