如何避免Java向下倾斜?

时间:2014-05-22 20:21:43

标签: java downcast

我目前正在开发一个项目,我有3个用户类,比如UserA,UserB,UserC,它们是从一个抽象的User类继承的。

该程序应该模拟系统愿望,要求用户登录和注销。

这些用户的实例存储在3个单独的列表中。

任何时候只有一个用户被“记录”,所以我有一个User currentUser变量。

当我想调用特定于UserA,B或C的方法时,我会进行强制转换。 如何在保持代码优雅的同时避免进行演员表?

代码:

public abstract class User {
}

public class UserA extends User {
    public void clearAgenda();
}

public class UserB extends User {
}

public class UserC extends User {
}

public class System {
    private User loggedUser;

    public void clearUserAgenda() {
        ((UserA) loggedUser).clearAgenda();
    }
}

注意: 我事先知道如果正在使用某个操作,则当前用户支持该操作。 (例如:如果调用System.clearUserAgenda(),则用户是UserA的实例)

3 个答案:

答案 0 :(得分:4)

如果要避免强制转换,则必须在抽象类用户中声明方法clearAgenda()。如果你不这样做,只有UserS可以使用这种方法,所以必须进行铸造。

答案 1 :(得分:3)

你几乎有两个选择:

  1. 使用反射,但几乎取消了“保持代码清洁”的要求。
  2. 让所有用户遵守通用界面(即将clearAgenda()放入User,提供默认的空白实施并在UserA中覆盖它。对所有方法都这样做。
  3. 我建议选项2.您遇到了这个难题,因为您要让System班的来电者知道您拥有哪种类型的用户。 System然后假设调用者是正确的(这在现实世界中是一个非常糟糕的假设)并且盲目地调用该方法。如果System无法知道,那就没关系,但它需要能够处理用户在错误的用户上调用错误的方法。为此,在clearAgenda()上致电UserB并不是错误的。在超类方法中,您可以只记录该方法被调用而不被覆盖,这样您就能够检测到问题,而不会因为强制转换异常而导致整个事件崩溃。

答案 2 :(得分:3)

这是一个明确的多态性案例。您可以在User中声明该方法(如Baalthasarr所说),然后根据需要在子类型(UserA,UserB等)中覆盖它。然后你只需使用loggedUser.clearAgenda(),JRE将确定在运行时自动使用哪种方法。

public abstract class User {
    public void clearAgenda() {} // do nothing (or or something if you want)
}

public class UserA extends User {
    @Override public void clearAgenda() { ... } // do stuff specific to A
}

public class UserB extends User {
    @Override public void clearAgenda() { ... } // do stuff specific to B
}

public class UserC extends User {
}

public class System {
    private User loggedUser;

    public void clearUserAgenda() {
        // This will use the most appropriate method. If the type is
        // UserA, UserA's `clearAgenda` method will be used. Similar
        // for UserB. For UserC, The abstract User class's `clearAgenda`
        // method is used, because it was not overridden in UserC.
        loggedUser.clearAgenda();
    }
}

如果您想要对所有用户子类执行此操作,则可以将其置于用户中,即使您覆盖该方法仍然可以运行它。例如:

public class UserA extends User {
    @Override public void clearAgenda() {
        super.clearAgenda(); // do the stuff common to all User subclasses
        ... // do stuff specific to A
    }
}