我目前正在开发一个项目,我有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的实例)
答案 0 :(得分:4)
如果要避免强制转换,则必须在抽象类用户中声明方法clearAgenda()
。如果你不这样做,只有UserS可以使用这种方法,所以必须进行铸造。
答案 1 :(得分:3)
你几乎有两个选择:
clearAgenda()
放入User
,提供默认的空白实施并在UserA中覆盖它。对所有方法都这样做。我建议选项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
}
}