문제

비동기 원격 인터페이스를 노출하는 가장 좋은 방법에 대한 질문이 있습니다.

조건은 다음과 같습니다.

  • 프로토콜은 비동기식입니다.
  • 제3자는 언제든지 데이터를 수정할 수 있습니다.
  • 명령 왕복은 중요할 수 있습니다.
  • 모델은 UI 상호작용에 매우 적합해야 합니다.
  • 프로토콜은 특정 개체에 대한 쿼리를 지원하므로 모델도 마찬가지입니다.

이 분야에서 부족한 기술을 개선하고 Java 전반을 향상시키기 위한 수단으로 저는 프로젝트 Eclipse 기반 프런트엔드를 만들기 위해 xmms2 (아래에서 묘사 되어진).

그래서 질문은 다음과 같습니다.원격 인터페이스를 깔끔한 데이터 모델로 노출하려면 어떻게 해야 합니까(이 경우 트랙 관리 및 이벤트 처리)?

일반적인 토론부터 패턴 이름 삭제 또는 구체적인 예제 및 패치에 이르기까지 무엇이든 환영합니다 :)


여기서 나의 주요 목표는 일반적으로 이러한 종류의 문제에 대해 배우는 것입니다.내 프로젝트가 그것으로부터 이득을 얻을 수 있다면 괜찮습니다. 하지만 토론을 시작할 무언가를 갖기 위해 엄격하게 제시합니다.

나는 내가 호출하는 프로토콜 추상화를 구현했습니다. '고객' (레거시 이유로) 완벽하지는 않더라도 만족스러운 메서드 호출을 사용하여 대부분의 노출된 기능에 액세스할 수 있습니다.

xmms2 데몬이 제공하는 기능으로는 트랙 검색, 메타데이터 검색 및 조작, 재생 상태 변경, 재생 목록 로드 등과 같은 기능이 있습니다.

나는 xmms2의 최신 안정 릴리스로 업데이트하는 중이며 현재 구현의 눈에 띄는 약점 중 일부를 수정하는 것이 좋겠다고 생각했습니다.

내 계획은 프로토콜 인터페이스 위에 더 나은 추상화를 구축하여 데몬과 보다 자연스러운 상호 작용을 가능하게 하는 것입니다.현재 '모델' 구현은 사용하기 어렵고 솔직히 매우 보기 흉합니다(정말로 끔찍한 ATM인 UI 코드는 말할 것도 없고).

오늘 나는 트랙 인스턴스를 가져오는 데 사용할 수 있는 인터페이스 ID를 기반으로 한 클래스입니다.검색은 다음을 통해 수행됩니다. 컬렉션 인터페이스(불행한 네임스페이스 충돌)를 트랙으로 옮기고 싶다고 생각합니다.

모든 데이터는 언제든지 제3자에 의해 수정될 수 있으며, 이는 모델에 적절하게 반영되고 변경 알림이 배포되어야 합니다.

이러한 인터페이스는 연결 시 다음과 같은 개체 계층 구조를 반환하여 노출됩니다.

  • 연결
    • 재생 getPlayback()
      • 재생, 일시 정지, 점프, 현재 트랙 등
      • 재생 상태 변경 노출
    • 트랙 getTracks()
      • getTrack(id) 등 추적
      • 트랙 업데이트 노출
    • 컬렉션 getCollection()
      • 재생 목록 또는 명명된 컬렉션 로드 및 조작
      • 미디어 라이브러리 쿼리
      • 컬렉션 업데이트 노출
도움이 되었습니까?

해결책

비동기 비트의 경우 다음을 확인하는 것이 좋습니다. java.util.concurrent, 그리고 특히 Future<T> 상호 작용.future 인터페이스는 아직 준비되지 않았지만 별도의 스레드에서 생성되는 개체를 나타내는 데 사용됩니다.객체는 제3자에 의해 언제든지 수정될 수 있다고 말씀하셨지만 여기서는 불변 반환 객체를 사용하고 대신 객체가 만료될 때 알림을 받을 수 있도록 구독할 수 있는 별도의 스레드/이벤트 로그를 갖는 것이 좋습니다.저는 UI 프로그래밍이 거의 없지만 비동기 호출에 Futures를 사용하면 서버 응답을 기다리는 GUI가 아닌 반응형 GUI를 갖게 될 것이라고 믿습니다.

쿼리의 경우 메서드 체이닝을 사용하여 쿼리 개체를 구축할 것을 제안하고 메서드 체이닝에 의해 반환된 각 개체는 다음과 같아야 합니다. Iterable.Djangos 모델과 유사합니다.당신이 가지고 있다고 말해 QuerySet 구현하는 Iterable<Song>.그런 다음 전화할 수 있습니다. allSongs() 그러면 모든 노래에 대해 반복되는 결과가 반환됩니다.또는 allSongs().artist("Beatles"), 그리고 모든 Betles 노래에 대해 반복 가능을 갖게 됩니다.또는 allSongs().artist("Beatles").years(1965,1967) 등등.

이것이 출발점으로 도움이 되기를 바랍니다.

다른 팁

Iterable에는 Iterator get() 등의 메서드만 있습니다.따라서 실제로 반복을 시작할 때까지 쿼리를 작성하거나 코드를 실행할 필요가 없습니다.귀하의 예제에서 실행이 중복되게 만듭니다.그러나 첫 번째 결과를 사용할 수 있을 때까지 스레드가 잠기므로 실행자를 사용하여 별도의 스레드에서 쿼리에 대한 코드를 실행하는 것을 고려할 수 있습니다.

@스탈레

확실히 그럴 수도 있지만, 언급했듯이 그렇게 하면 (집에서 수면 디스크로 인해 10초 동안) 차단될 수 있으므로 이를 사용하여 UI를 직접 업데이트할 수 없습니다.

반복자를 사용하여 별도의 스레드에서 결과 복사본을 만든 다음 이를 UI로 보낼 수 있지만 반복자 솔루션 자체는 다소 우아하지만 잘 맞지 않습니다.결국 뭔가 구현 IStructuredContentProvider 개체를 표시하려면 모든 개체의 배열을 반환해야 합니다. 테이블뷰어, 그래서 콜백에서 그런 것을 가져오는 것으로 벗어날 수 있다면...:)

좀 더 생각해 보겠습니다.내가 뭔가를 해결할 수 있을지도 몰라.코드가 보기 좋게 보입니다.

@스탈레:무리 감사!

비동기 작업에 Future를 사용하는 것은 흥미롭습니다.유일한 단점은 콜백을 제공하지 않는다는 것입니다.하지만 다시 한 번 그 접근 방식을 시도했고 그 결과가 어떻게 되었는지 살펴보겠습니다. :)

현재 작업자 스레드와 들어오는 명령 응답을 전달하기 위한 차단 대기열을 사용하여 비슷한 문제를 해결하고 있지만 해당 접근 방식은 잘 변환되지 않습니다.

원격 개체는 수정될 수 있지만 스레드를 사용하므로 개체를 변경할 수 없도록 유지하려고 합니다.내 현재 가설은 양식의 트랙 업데이트에 대한 알림 이벤트를 보내는 것입니다.

somehandlername(int changes, Track old_track, Track new_track)

또는 유사하지만 동일한 트랙의 여러 버전이 생길 수도 있습니다.

Djangos 메소드 체이닝을 꼭 살펴보겠습니다.비슷한 구성을 몇 개 살펴봤지만 좋은 변형을 찾지 못했습니다.반복 가능한 항목을 반환하는 것은 흥미롭지만 쿼리를 완료하는 데 시간이 걸릴 수 있으므로 쿼리가 완전히 구성되기 전에 실제로 쿼리를 실행하고 싶지 않습니다.

아마도 다음과 같은 것

Tracks.allSongs().artist("Beatles").years(1965,1967).execute()

Future를 반환하면 작동할 수도 있습니다...

지금까지 내 결론은;

개체가 불변이기 때문에 Track 개체에 게터를 사용할지 아니면 멤버만 노출할지 고민됩니다.

class Track {
    public final String album;
    public final String artist;
    public final String title;
    public final String genre;
    public final String comment;

    public final String cover_id;

    public final long duration;
    public final long bitrate;
    public final long samplerate;
    public final long id;
    public final Date date;

    /* Some more stuff here */
}

라이브러리의 트랙에 무슨 일이 일어났는지 알고 싶은 사람이라면 누구나 이것을 구현할 것입니다...

interface TrackUpdateListener {
    void trackUpdate(Track oldTrack, Track newTrack);
}

이것이 쿼리가 작성되는 방식입니다.마음에 쏙 드는 연쇄 통화를 즐겨보세요.하지만 배심원단은 아직 get()을 진행 중입니다.와일드카드를 처리하는 방법과 분리를 사용하여 고급 쿼리를 처리하는 방법과 같은 몇 가지 세부 정보가 누락되었습니다.아마도 다음과 유사한 일부 완료 콜백 기능이 필요할 수도 있습니다. 비동기 완료 토큰, 하지만 그것에 대해서는 살펴보겠습니다.아마도 그것은 추가 레이어에서 일어날 것입니다.

interface TrackQuery extends Iterable<Track> {
    TrackQuery years(int from, int to);
    TrackQuery artist(String name);
    TrackQuery album(String name);
    TrackQuery id(long id);
    TrackQuery ids(long id[]);

    Future<Track[]> get();
}

몇 가지 예:

tracks.allTracks();
tracks.allTracks().artist("Front 242").album("Tyranny (For You)");

트랙 인터페이스는 대부분 연결과 개별 트랙 사이의 접착제일 뿐입니다.메타데이터 캐싱이 있는 경우 이를 구현하거나 관리하는 역할이 될 것입니다(오늘과 같지만 리팩토링 중에 제거하고 실제로 필요한지 확인하겠습니다).또한 이것은 트랙별로 구현하기에는 너무 많은 작업이 필요하므로 medialib 트랙 업데이트를 제공합니다.

interface Tracks {
    TrackQuery allTracks();

    void addUpdateListener(TrackUpdateListener listener);
    void removeUpdateListener(TrackUpdateListener listener);
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top