【问题标题】:Java casting interface but using object methodsJava 转换接口但使用对象方法
【发布时间】:2017-05-03 12:31:50
【问题描述】:

我有一个关于如何在通过接口实例化时调用对象基成员的问题。

假设我正在尝试构建的框架中有以下接口和具体类:

public interface UsedClass {
    public boolean getBool();
}

public class User implements UsedClass {

    private String userName;
    private String userRole;
    public User(String userName, String userRole){
       this.userName = userName;
       this.userRole = userRole;
     }
    public boolean getBool() {
        // some code
    }
    public int getUserName() {
        return userName;
    }
    public int getUserRole() {
        return userRole;
    }

还有一个实现类:

public class Run implements UsedClass {        
    private String runName;
    private int runNumber;
    public Run(String runName, int runNumber){
       this.runName = runName;
       this.runNumber = runNumber;
     }
    public boolean getBool() {
        // some code
    }
    public String getRunName() {
        return runName;
    }
    public int getRunNumber() {
        return runNumber;
    }
}

但我不能将方法getRunName()getUserRole() 放入接口!

最终目标是创建一个 FactoryClass 来处理从数据库 GUI 传递的对象。

我想知道是否有更好的方法,然后使用类引用能够安全地调用 Run 或 User 的方法,例如:

public class EntityFactory {
  public static Object getValueAt(int rowIndex, int columnIndex, UsedClass usedClass) {
        if (usedClass.getClass().getSimpleName().equals("User")) {

            switch (columnIndex) {
            case 0:
                return ((User) usedClass).getUserName();
            case 1:
                return ((User) usedClass).getUserRole();
            default:
                return null;
            }
        } else if (usedClass.getClass().getSimpleName().equals("Run")) {
            switch (columnIndex) {
            case 0:
                return ((Run) usedClass).getRunName();
            case 1:
                return ((Run) usedClass).getRunNumber();
            default:
                return null;
    }
}

我已经阅读了几篇 SO 帖子 type casting when objects are of interface references in JavaJava cast interface to class

暗示不建议引用转换,但由于我不能将所有方法都放入接口中,建议什么?

【问题讨论】:

  • 至少使用usedClass instanceof User 而不是usedClass.getClass().getSimpleName().equals("User")
  • 也许您可以在接口中添加一些getValueAt(int columnIndex) 方法并在子类中实现它?
  • 杰斯珀:谢谢。 Berger:但是在单个类中拥有这个 getValueAt 更加面向对象。至少我是这么认为的。
  • 不要使用字符串来识别这样的类。你失去了所有类型的安全性。这不是面向对象的编程。你的类型系统是错误的。您需要一个接口,允许客户端类使用它而无需向下转换或任何instanceof 垃圾。
  • 如果不了解您为什么这样做的更多细节,就没有正面的例子。但是@LewBloch 是正确的,这不是做事的好方法。

标签: java interface casting


【解决方案1】:
static interface ColumnSource<T> {
    String getColumn(T value, int index);
}
static Map<Class, ColumnSource> map = new HashMap();
static {
    map.put(User.class, new UserNameAndRoleSource<User>() {
        public String getColumn(User user, int index) { 
            switch (index) {
                case 0: return user.getUserName(); 
                case 1: return user.getUserRole(); 
                default: throw new RuntimeException();
            }
        }
    });
    map.put(Run.class, new ColumnSource<Run>() {
        public String getColumn(Run run, int index) { 
            switch (index) {
                case 0: return run.getRunName(); 
                case 1: return run.getRunNumer();
                default: throw new RuntimeException();
            }
        }
    });
}
public static Object getValueAt(int rowIndex, int columnIndex, Object o) {
   Class type = o.getClass();
   ColumnSource source = map.get(type);
   if (source == null) throw new RuntimeException(type.getName() + " not supported"); 
   return source.getColumn(o, columnIndex);
}

【讨论】:

  • 这并不能解决问题,因为接口将实现 Run 或 User 不使用的方法。例如 Run 没有方法 getUserRole()。
  • 更新到ColumnSource.getColumn(T value, int index)
  • 这很好,但也有一些方法返回一个字符串和一些整数的问题。因此,即使在不同返回类型的接口中添加另一个方法,getValueAt 方法也可能会返回一些异常,因为在 User 中没有类型,而在 Run 中。
【解决方案2】:

您应该使用instanceof 而不是查看类的simpleName

除此之外,您是正确的。您要么需要一个包含常用方法的接口,然后可以调用它们,要么您需要确定该对象是特定类的实例,然后进行强制转换并进行方法调用。

您可以考虑使用Map&lt;Class&lt;? extends UsedClass&gt;, Map&lt;Integer, Function&lt;___&gt;&gt;&gt; 处理程序。

那么你的处理将是

handlers.get(usedClass.getClass()).get(columnIndex).apply(usedClass);

显然,您需要考虑如何处理意外的类/索引情况。内部的Map&lt;Integer,... 可能是List&lt;...&gt;,具体取决于它的使用方式。

【讨论】:

  • 我认为这张地图是个好主意,但我无法将其概念化。一旦我了解它,我可能会将其标记为可接受的答案。
【解决方案3】:

两件事:

  • 如果有的话,您使用 instanceof 而不是字符串/类名比较
  • 您将接口/类构建为有用。它们是您正在做的所有事情的基础。如果你从破碎的抽象开始,你就破碎了。就这么简单。

我的意思是:如果有“共同”的行为;那么你应该使用 common 接口来表达这一点。如果没有,你就在一个已经破碎的基础上开始你的努力;并且您将需要在各处创建“创造性的解决方法”,以对抗该疾病的症状

也许一个小的解决方案可能是至少有多个接口,比如

interface UsedClass { ...

interface SpecialUsedClassA extends UsedClass { ...

interface SpecialUsedClassB extends UsedClass { ...

你至少可以返回 UsedClass 而不是 Object。

【讨论】:

  • 这个项目的共同行为是在一个界面中。但是,我试图为实现 UsedClass 的所有类的所有 getter 提取不常见的行为,例如 run.getRunName() 和 user.getUserRole...等。如果实现的数量很少,您的解决方法是“创造性的”和实用的。但是,对于我的项目,我实际上有 23 个类,它们实际上是持久性实体。因此,我觉得拥有 23 个“特殊”接口对于该领域的新手来说是相当乏味和困惑的。
  • 我明白了。仍然是一个很好,有趣的问题。反正;我能做些什么让我的回答在你眼中至少值得投票吗? (不,我现在对接近 23 个接口没有一个好主意)。
猜你喜欢
  • 2013-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多