【问题标题】:Java - cast to an interface, then find out what the casted type isJava - 转换为接口,然后找出转换的类型是什么
【发布时间】:2016-03-14 07:35:24
【问题描述】:

我在类转换方面有点挣扎。让我设置场景。我有使用服务和编排器层的 java 服务器代码。请求以 bean 格式(与前端视图对齐的 java 类)进入服务层,然后我有一堆 domainBeanMapper 类,它们采用 bean 格式对象并将其转换为域格式对象。例如,UserBean 有一个由字符串表示的 dateOfBirth,而 User 有一个由 Date 表示的 dateOfBirth,因此 UserMapper.java 会将日期字符串转换为日期对象。因此,对于系统中的每个对象,我都有一个 *.java、*Bean.java 和 *Mapper.java(User.java、UserBean.java、userMapper.java)。

在 applicationContext 中,我保存每个对象与其映射器的关系,如下所示:

<util:map id="domainBeanMappers">   
    <entry key="UserBean" value-ref="userMapper" />
    <entry key="User" value-ref="userMapper" />
.....

然后我定义映射器:

<bean id="userMapper" class="com.me.mapping.UserMapper" parent="baseDomainBeanMapper"/>

我从我的服务层这样调用域 bean 映射器:

UserBean userBean = (UserBean) getDomainBeanMapper().mapDomainToBean(user);

在运行这段代码时,我找到了我想要的映射器对象,如下所示:

    DomainBeanMapper mapper = findApplicableMapper(myObject.getClass().getName());
    if (mapper == null) {
        mapper = findApplicableMapper(myObject.getClass().getSimpleName());
    }

findApplicableMapper 的工作方式如下:

private DomainBeanMapper findApplicableMapper(String string) {
    return domainBeanMappers.get(string);
}

在过去的几年里,这就像一个魅力。对于系统中我想要的任何对象,我可以轻松地挑选出相关的映射器,然后根据任何实例的 .getClass() 调用从我的 bean 格式转换为域格式,反之亦然。

现在,我有一个新要求给我带来了麻烦。我希望能够根据参数从我的用户对象转换为多个子对象。所以对于一些电话,我只想要 id、firstName 和 lastName 回来。对于其他调用,我想要更多字段,但仍然不是整个对象,然后对于某些调用,我希望整个对象像以前一样返回。我不想沿着子对象的路径走下去,最终得到 UserLight、UserLightWithName、UserLightWithNameButNoAddress,……啊,噩梦。

因此,我希望创建一堆代表“视图”的接口。所以请求带有 Basic 的 ViewType,这意味着我想要用户的个人详细信息和地址。于是我写了一个叫 UserBasic 的接口,让 User 实现它,并添加了从 UserBasic 到 UserBasicMapper,从 UserBasicBean 到 UserBasicMapper 的映射,希望我可以像这样进行翻译调用:

UserBasicBean restrictedUserReturn = (UserBasicBean) getDomainBeanMapper().mapDomainToBean((UserBasic)user);

但这不起作用,因为 getClass() 总是返回实例类,而不是它被转换到的接口。我想我总是可以在 mapDomainToBean 调用中添加另一个参数,这是我想要使用的类,但是代码库非常庞大,如果我进行更改,我将需要处理每个调用。

所以基本上我正在寻找一种将实例转换为接口类型然后找到该接口类型的方法?这可能吗??

交叉手指...

【问题讨论】:

  • 为什么不想要整个对象?
  • 这是一项安全要求。系统的某些用户只能看到对象的某些部分。

标签: java interface casting


【解决方案1】:

与其制作用户实现的接口,不如制作代表受限版本的代理类?例如,

class UserBasic {

    private User user;

    public UserBasic(User user) {
        this.user = user;
    }

    public String getFirstName() {
        return user.getFirstName();
    }
    ...
}

然后您可以添加getUser() { return user; } 以获取完整实例。

通过这种方式,您应该能够保持其他所有内容不变,并为类而不是接口做出权衡。

【讨论】:

  • 哦,这很好!!!它将为我提供相同的功能,而且我根本不需要更改 domainBeanMapper 代码。 UserBasic 也可以有一个 getUser() 方法来允许我映射到另一个方向 - 对于提供子对象视图的请求。是的,这很棒!
  • 哈哈,太好了,您在我写评论时添加了 getUser 部分。非常感谢您的宝贵时间!
  • 很高兴为您提供帮助! @玛格丽特
  • 工作就像一个魅力,谢谢。 UserBasicBean restrictedUserReturn = (UserBasicBean) getDomainBeanMapper().mapDomainToBean(new UserBasic(user));
【解决方案2】:

我不确定,但您可以使用 instanceof 关键字来检查它是哪种类型的对象。

【讨论】:

  • 不幸的是,这并没有真正起作用,因为我不得不说 if (myObject instanceOf UserBasic) { mapper = findApplicableMapper("UserBasic"); } else if (myObject instanceOf AnotherView) { ..... } 这真的会弄脏我的代码。谢谢你的想法。
  • 我正在寻找的是一种利用 instanceOf 实现背后的代码来找出 myObject 的实例的方法。这似乎很愚蠢,这将不可用
【解决方案3】:

您可以编写一些与参数类型不同的方法,例如:

public class Test
{

    public static void n(Number n) {
        System.out.println("Number");
    }

    public static void n(Integer n) {
        System.out.println("Integer");
    }

    public static void main(String[] args)
    {
        n(3); //will call the n(Integer n);
        n((Number)3); //will call the n(Number n);
    }
}

所以是的,您可以通过创建多个方法,每个方法都采用正确的参数类型,然后根据类型对其进行相应的处理,从而找出您转换为哪种类型。

【讨论】:

  • 不幸的是我不相信我可以使用这条路。我将让我的对象为不同的视图实现多个接口。所有这些都将是成员变量的相关 getter 和 setter 的重叠集。例如。用户实现 UserBasic、UserLight、UserLocation。然后,如果我使用 instanceof 检查,它将为所有检查返回 true,因为 User 对象实现了所有检查。而不是检查我刚刚将其转换为什么类型。这有意义吗?我需要找出刚才投射的具体界面。
【解决方案4】:

界面不代表视图 - 它定义了一种行为。 我想你需要某种工厂(请查看这些链接以获取灵感https://en.wikipedia.org/wiki/Factory_method_patternhttps://sourcemaking.com/design_patterns/abstract_factory)这里(或建造者) 如果你说“子对象” - 尝试扩展 UserBean 类

class BaseUserBean extends UserBean {}
class AnotherUserBean extends UserBean {}

将所有用户的通用内容放入基类中,将每个子用户真正特定的内容放入子类中,然后

 UserBean u = getDomainBeanMapper().mapDomainToBean(user);

...

//method mapToDomain should check your param and return the type you need
//ViewType can be a part of user or a separate param
UserBean mapDomainToBean(User user, ViewType vt) {
    if (vt == ViewType.BASE) {
      BaseUserBean obj = BaseUserBean ();
      // mapping here (set fields you need)
      return obj;
    }

    if (vt == ViewType.ANOTHER) {
      AnotherUserBean obj = AnotherUserBean ();
      // mapping here (set fields you need)
      return obj;
    }
    ...
}

【讨论】:

  • 这当然是可能的,谢谢,但是更改 mapDomainToBean 签名会影响数百个点,目前没有时间对整个系统进行过仔细的回归测试。
猜你喜欢
  • 2011-12-14
  • 1970-01-01
  • 2016-04-02
  • 1970-01-01
  • 2014-05-03
  • 2015-06-08
  • 1970-01-01
  • 2010-10-11
  • 1970-01-01
相关资源
最近更新 更多