GUI가 없습니다 (제 수업은 Minecraft Mod의 일부입니다). C # 이벤트 프레임 워크를 모방 할 수 있기를 원했습니다. 클래스는 이벤트를 선언하고 다른 사람들이 이벤트를 구독 할 수 있도록합니다.
내 첫 번째 접근 방식은라는 클래스 EventArgs
를 만든 다음 다음과 같이하는 것이 었습니다 .
public class EventArgs
{
public boolean handled;
}
@FunctionalInterface
public interface IEventHandler<TEvtArgs extends EventArgs>
{
public void handle(Object source, TEvtArgs args);
}
public class Event<TEvtArgs extends EventArgs>
{
private final Object owner;
private final LinkedList<IEventHandler<TEvtArgs>> handlers = new LinkedList<>();
public Event(Object owner)
{
this.owner = owner;
}
public void subscribe(IEventHandler<TEvtArgs> handler)
{
handlers.add(handler);
}
public void unsubscribe(IEventHandler<TEvtArgs> handler)
{
while(handlers.remove(handler));
}
public void raise(TEvtArgs args)
{
for(IEventHandler<TEvtArgs> handler : handlers)
{
handler.handle(owner, args);
if(args.handled)
break;
}
}
}
그런 다음 클래스는 다음과 같이 할 것입니다.
public class PropertyChangedEvtArgs extends EventArgs
{
public final Object oldValue;
public final Object newValue;
public PropertyChangedEvtArgs(final Object oldValue, final Object newValue)
{
this.oldValue = oldValue;
this.newValue = newValue;
}
}
public class SomeEventPublisher
{
private int property = 0;
private final Random rnd = new Random();
public final Event<PropertyChangedEvtArgs> PropertyChanged = new Event<>(this);
public void raiseEventOrNot(int value)
{
if(rnd.nextBoolean())//just to represent the fact that the event is not always raised
{
int old = property;
property = value;
PropertyChanged.raise(new PropertyChangedEvtArgs("old(" + old + ")", "new(" + value + ")"));
}
}
}
public class SomeSubscriber
{
private final SomeEventPublisher eventPublisher = new SomeEventPublisher();
public SomeSubscriber()
{
eventPublisher.PropertyChanged.subscribe(this::handlePropertyAChanges);
}
private void handlePropertyAChanges(Object source, PropertyChangedEvtArgs args)
{
System.out.println("old:" + args.oldValue);
System.out.println("new:" + args.newValue + "\n");
}
public void someMethod(int i)
{
eventPublisher.raiseEventOrNot(i);
}
}
public class Main
{
private static final SomeSubscriber subscriber = new SomeSubscriber();
public static void main(String[] args)
{
for(int i = 0; i < 10; ++i)
{
subscriber.someMethod(i);
}
}
}
이 순진한 접근 방식의 가장 큰 문제 raise
는 공개적 으로 노출 하여 적절한 캡슐화를 깨뜨리는 것 입니다. 나는 그 주변의 길을 볼 수 없으며 아마도 내 전체 패턴이 잘못되었을 수 있습니다. 몇 가지 아이디어를 원합니다.
관련 문제도있다 : 나는 이벤트가 즉시 제기 할 싶습니다 후 그 수익을 올리는 방법. 스레드 또는 다른 구성을 사용하여 이것을 동기화하는 방법이 있습니까? 물론 호출자 코드는 동기화 작업에 포함될 수 없습니다. 완전히 투명해야합니다.
여기서 가장 좋은 방법은 처음에 자체 이벤트 프레임 워크를 구현하지 않고 기존 라이브러리에 의존하는 것입니다. 기본적으로 Java는를 제공 EventListener
하며 최소한 여기에 문서화 된 패턴을 따를 수 있습니다. 비 GUI 응용 프로그램의 경우에도이 조언의 대부분이 적용됩니다.
JDK Guava를 넘어 서면 정확한 사용 사례에 따라 몇 가지 가능한 옵션이 제공됩니다.
가장 가능성이 높은 후보는 다음 EventBus
과 같습니다.
구성 요소가 서로 명시 적으로 등록 할 필요없이 (따라서 서로를 인식 할 필요없이) 구성 요소 간의 게시-구독 스타일 통신을 허용합니다.
또는 ListenableFuture
(및 ListeningExecutorService
) 다음 중 :
[에 제출 된 작업
Executor
]이 완료되면 또는 계산이 이미 완료된 경우 즉시 실행할 콜백을 등록 할 수 있습니다 . 이 간단한 추가를 통해 기본 Future 인터페이스가 지원할 수없는 많은 작업을 효율적으로 지원할 수 있습니다.
또는 다음과 같은 Service
API :
시작 및 중지 방법이있는 작동 상태의 개체를 나타냅니다. 예를 들어 웹 서버, RPC 서버 및 타이머는 서비스 인터페이스를 구현할 수 있습니다. 적절한 시작 및 종료 관리가 필요한 이와 같은 서비스의 상태를 관리하는 것은 특히 여러 스레드 또는 일정이 관련된 경우에는 사소한 일이 아닙니다.
이 API를 사용하면 리스너 를 등록 하여 서비스의 상태 변경에 응답 할 수 있습니다.
이러한 옵션이 사용 사례에 직접 작동하지 않더라도 Guava의 소스 코드 에서 이벤트 기반 동작 및 에뮬레이션 할 수있는 리스너의 예를 살펴보십시오.
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다