Java에서 여러 일반 인터페이스 구현


10

특정 서명을 포함한 특정 방법을 사용할 수있는 인터페이스가 필요합니다. 지금까지 내가 가진 것은 다음과 같습니다.

public interface Mappable<M> {
    M mapTo(M mappableEntity);
}

클래스를 여러 다른 엔티티에 맵핑 할 수 있어야 할 때 문제가 발생합니다. 이상적인 경우는 다음과 같습니다 (Java가 아님).

public class Something implements Mappable<A>, Mappable<B> {
    public A mapTo(A someObject) {...}
    public B mapTo(B someOtherObject) {...}
}

이것을 "일반적인"상태로 유지하는 가장 좋은 방법은 무엇입니까?

답변:


10

물론 이것은 Type Erasure 로 인해 할 수있는 일이 아닙니다 . 런타임 public Object mapTo(Object)에는 공존 할 수없는 두 가지 방법 이 있습니다.

불행히도, 당신이하려는 것은 단순히 Java 유형 시스템을 넘어서는 것입니다.

제네릭 형식이 항상 첫 번째 클래스 형식이고 일반 형식이 아니라고 가정하면 메서드를 사용하여 비슷한 바깥 쪽을 향한 동작 mapTo(Object, Class)을 수행 할 수 있습니다. 이렇게하면 지정된 클래스의 런타임 검사를 수행하고 사용할 동작을 결정할 수 있습니다. 분명히 이것은 매우 우아하지 않으며 반환 값을 수동으로 캐스팅해야하지만 최선의 방법이라고 생각합니다. 제네릭 형식이 제네릭이면 제네릭 매개 변수도 지워지고 클래스가 동일하므로이 방법이 작동하지 않습니다.

그러나 @Joachim의 대답을 지적 할 것입니다. 이것은 동작을 분리 된 구성 요소로 나누고 전체 문제를 회피 할 수있는 경우 일 수 있습니다.


3

보시다시피, 다른 유형 매개 변수를 사용하여 동일한 인터페이스를 두 번 구현할 수 없습니다 (지우기 때문에 : 런타임에 인터페이스가 동일 함).

또한이 접근법은 단일 책임 원칙을 위반합니다. 클래스는 Something(그것이 무엇이든간에) 중점을 두어야하며 해당 작업 에 매핑 A하거나 해당 작업 B 을 추가 해서는 안됩니다 .

당신이 정말로 a Mapper<Something,A>와 a을 가져야 할 것 같습니다 Mapper<Something,B>. 이런 식으로 각 클래스에는 명확하게 정의 된 단일 책임이 있으며 동일한 인터페이스를 두 번 구현하는 문제는 발생하지 않습니다.


글쎄, 아이디어는 클래스가 그 내용을 다른 객체로 "변환"하는 책임을지게하는 것입니다. 그런 다음 클래스와 무관하게 처리하는 디스패처가 있으므로 제네릭 요구 사항이 있습니다. 나는 논리를 추출하는 것에 대해 조금 생각할 것입니다. 실제로 클래스를 두 개로 나눕니다. 그러나 그들은 밀접하게 결합되어 있습니다 (필드에 대한 액세스 권한이 부여되어야하며, 대부분의 시간을 수정해야 다른 시간을 수정하는 등)
— estani

@estani : 그렇습니다. 그들은 다소 밀접하게 결합되어 있지만 뚜렷한 책임이 있습니다. 또한 이것에 대해 생각하십시오 : 새로운 클래스를 소개하고 C그에 Something매핑 할 수 있으 려면 Something너무 많은 커플 링 인 수정해야합니다 . 새로운 것을 추가하는 것만으로 SoemthingToCMapper는 덜 방해가됩니다.
— Joachim Sauer

1
+1-일반적으로 말하면 OP에서 원하는 것을 달성하려는 경우 (자바에서) 상속보다 구성을 선호해야합니다. 기본 방법을 사용하는 Java 8을 사용하면 더 쉽게 할 수 있지만 모든 사람들이 아직 최첨단을 뛰어 넘을 수는 없습니다. :-).
— Martijn Verburg

0

다중 인터페이스를 구현할 수 없으므로 캡슐화 사용을 고려할 수 있습니다. (java8 +를 사용하는 예)

// Mappable.java
public interface Mappable<M> {
    M mapTo(M mappableEntity);
}

// TwoMappables.java
public interface TwoMappables {
    default Mappable<A> mapableA() {
         return new MappableA();
    }

    default Mappable<B> mapableB() {
         return new MappableB();
    }

    class MappableA implements Mappable<A> {}
    class MappableB implements Mappable<B> {}
}

// Something.java
public class Something implements TwoMappables {
    // ... business logic ...
    mapableA().mapTo(A);
    mapableB().mapTo(B);
}

추가 정보 및 추가 예는 여기를 확인하십시오. 두 가지 일반 유형으로 하나의 인터페이스를 구현하는 Java 클래스를 작성하는 방법은 무엇입니까? .


-1
public interface IMappable<S, T> {
    T MapFrom(S source);
}

// T - target
// S - source

User를 UserDTO에 매핑하고 User를 UserViewModel에 매핑하려면 두 가지 별도의 구현이 필요합니다. 이 모든 논리를 단일 클래스에 쌓아 두지 마십시오. 그렇게하는 것은 의미가 없습니다.

Joachim을 행복하게 유지하기 위해 업데이트

public interface ITypeConverter<TSource, TDestination>
{
    TDestination Convert(TSource source);
}

그러나 지금 우리는 Automapper 영역에 있습니다 ( http://automapper.codeplex.com/wikipage?title=Custom%20Type%20Converters )


나는 IMappable다른 것들을 매핑하는 것에 대한 좋은 이름 이라고 생각하지 않습니다 . Mapper(또는 IMapper, ;-) 해야하는 경우) 더 정확할 것입니다. (그런데 : 아니, 그건 내 공감대가 아니 었어).
— Joachim Sauer

나는 질문에있는 것을 가져 와서 인터페이스라는 사실을 강조하기 위해 I 접두사를 붙였습니다. 네이밍 문제가 아닌 질문에 따라 디자인 문제를 해결하고 있습니다.
— CodeART

1
미안하지만 내 생각으로는 디자인 문제를 "해결"하고 이름을 무시할 수는 없습니다. 디자인은 이해할 수있는 구조를 의미합니다. 잘못된 이름 지정은 이해하는 데 문제가됩니다.
— Joachim Sauer

업데이트 ;-) 나머지에 당신의 마음을 놓아야합니다
— CodeART

1
@CodeART 귀하의 답변을 올바르게 이해했다면 "MapFrom"(소문자 소문자 ;-)이 객체를 생성한다는 것을 의미합니다. 필자의 경우 이미 작성된 객체에 대한 정보를 채우는 것입니다.
— estani 10
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.