在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) {...}
}

什么是最好的方式来实现这种剩余的“通用”?

Answers:


10

当然,由于Type Erasure,您无法执行此操作。在运行时,您有两种方法public Object mapTo(Object)显然不能共存。

不幸的是,您试图做的事情超出了Java的类型系统。

假设您的泛型类型始终是第一类类型,而不是自身本身是泛型,则可以通过具有method来实现类似的向外行为mapTo(Object, Class),这将允许您对给定类进行运行时检查并决定要使用哪种行为。显然,这很不雅致-并需要手动转换返回值-但我认为这是您可以做的最好的事情。如果您的泛型类型本身就是泛型,那么它们的泛型参数也将被擦除,并且它们的类将相等,因此此方法将不起作用。

但是,我也将指向@Joachim的答案,在这种情况下,您可以将行为拆分为单独的组件并避开整个问题。


3

如您所见,您不能使用不同的类型参数来两次实现相同的接口(因为擦除:在运行时它们是相同的接口)。

而且,这种方法违反了单一责任原则:您的班级应该专注于成为Something(无论意味着什么)并且不应对该任务进行映射AB 除此之外

听起来您确实应该有一个Mapper<Something,A>和一个Mapper<Something,B>。这样,每个类都有一个明确定义的职责您不会遇到两次实现相同接口的问题。


好吧,这个想法是让类负责将其内容“转换”为其他对象。然后有一个调度程序以类不可知的方式处理它们,因此是泛型要求。我会考虑提取逻辑,尽管这实际上意味着我将类拆分为两个,但是它们保持紧密耦合(应允许访问字段,大部分时候修改一次暗示着修改另一个,等等)
estani

@estani:是的,他们之间紧密相连,但是他们有不同的责任。还要考虑一下:当您引入一个新类C并希望Something可以映射到该类时,则需要修改Something,这是太多的耦合。仅仅添加一个新的东西就SoemthingToCMapper不会那么麻烦。
约阿希姆·绍尔

1
+1-一般而言,如果要实现OP想要的功能(在Java中),您应该更倾向于使用组合而不是继承。带有默认方法的Java 8使这变得更加容易-但并不是每个人都可以跳到最前沿:-)。
马丁·维堡

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,如果必须的话,则为-))可能更正确。(顺便说一句:不,那不是我的不赞成)。
约阿希姆·绍尔

我已经回答了问题所在,并以I开头,以突出表明它是一个接口。我正在按问题解决设计问题,而不是命名问题。
CodeART

1
抱歉,但是我认为不能真正“解决”设计问题并忽略命名。设计意味着可以理解的结构。错误的命名是理解的问题。
约阿希姆·绍尔

更新应该让您放心;-)
CodeART 2013年

1
@CodeART如果我正确理解了您的答案,则暗示“ MapFrom”(应小写;-)创建对象。就我而言,它只是在已经创建的对象上填充信息。
estani 2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.