Java:在某些条件下构造子类的超类,可能吗?
我有这种情况Java:在某些条件下构造子类的超类,可能吗?,java,subclass,superclass,Java,Subclass,Superclass,我有这种情况 public class A { public action() { System.out.println("Action done in A"); } } public class B extends A { public action() { System.out.println("Action done in B"); } } 当我创建B的实例时,该操作将只执行B中的操作,因为它覆盖了超类的操作
public class A {
public action() {
System.out.println("Action done in A");
}
}
public class B extends A {
public action() {
System.out.println("Action done in B");
}
}
当我创建B的实例时,该操作将只执行B中的操作,因为它覆盖了超类的操作
问题是,在我的项目中,超级类A已经使用了太多次,我正在寻找一种方法,在某些情况下,当我创建A的实例时,它会进行检查,如果是真的,则用B替换它自己
public class A {
public A() {
if ([condition]) {
this = new B();
}
}
public action() {
System.out.println("Action done in A");
}
}
A a = new A();
a.action();
// expect to see "Action done in B"...
这在某种程度上是可能的吗?不是直接的,不是。调用
newa()
将始终创建A
的实例。但是,您可以使的构造函数受保护,然后使用静态方法:
public static A newInstance() {
// Either create A or B here.
}
然后将所有当前对构造函数的调用转换为对工厂方法的调用。如果使用。当您使用构造函数时:不,完全不可能。我认为这样做:
this = new B();
在的构造函数中,
将违反OO设计原则,即使它是可能做到的(事实并非如此)
也就是说,如果我面对这种情况:
问题是,在我的项目中,super class A已经被使用过很多次了
我将用以下两种方法之一解决它:
我假设您的条件是不需要太多类型A的对象,否则可以在任何其他条件下随意替换
选项1:使用工厂设计模式。
选项2:静态计数器+尝试和捕获
在a类中使用静态计数器,通过在构造函数中将静态变量增加1来跟踪a被实例化的次数。如果它达到类型a对象的最大数量限制,则在a的构造函数中抛出一个InstantiationError
这意味着,无论何时实例化A,都必须使用try..catch
块拦截InstantionError
,然后创建类型为B
的新对象
public class A {
private static count = 0;
private static final MAX_COUNT = 100;
public A() {
if (count > 100) {
throw new InstationError();
}
}
}
生成对象时:
A obj1, obj2;
try {
obj1 = new A();
} catch (InstantiationError ie) {
obj1 = new B();
}
try {
obj2 = new A();
} catch (InstantiationError ie) {
obj2 = new B();
}
选项2最接近您在问题中直接提出的问题。但是,我个人会选择使用工厂设计模式,因为它是更优雅的解决方案,它允许你实现你想做的事情。假设你不愿意将它移动到一个接口或工厂,它有点难看,但你可以在a中保留一个B的delegate副本,并重写你调用委托的方法:
public class A{
B delegate;
public A(){
if([condition]){
delegate = new B()
return;
}
...//normal init
}
public void foo(){
if(delegate != null){
delegate.foo();
return;
}
...//normal A.foo()
}
public boolean bar(Object wuzzle){
if(delegate != null){
return delegate.bar(wuzzle);
}
...//normal A.bar()
}
...//other methods in A
}
可以选择是否使用超类的构造函数?
不可能有条件地控制是否使用超类的构造函数,因为在构造自己的对象之前必须调用其中一个超类的构造函数
综上所述,Java中有一个要求,构造函数的第一行必须调用超类的构造函数——事实上,即使没有对超类构造函数的显式调用,也会有对super()
的隐式调用:
应该强调的是,在执行其他操作之后,不可能调用超类的构造函数:
public class Y extends X {
public Y() {
doSomething(); // Not allowed! A compiler error will occur.
super(); // This *must* be the first line in this constructor.
}
}
替代方案
也就是说,实现此处所需的方法可以是使用,它可以根据某种条件选择实现的类型:
public A getInstance() {
if (condition) {
return new B();
} else {
return new C();
}
}
class Main {
public static void main(String[] args) {
// Factory implementation will return ActionPerformerA
ActionPerformable ap = ActionPerformerFactory.getInstance(true);
// Invokes the action() method of ActionPerformable obtained from Factory.
ap.action();
}
}
在上述代码中,根据条件
,该方法可以返回B
或C
的实例(假设两者都是类a
的子类)
示例
下面是一个具体的示例,使用的是接口
,而不是类
设置以下接口和类:
interface ActionPerformable {
public void action();
}
class ActionPerformerA implements ActionPerformable {
public void action() {
// do something...
}
}
class ActionPerformerB implements ActionPerformable {
public void action() {
// do something else...
}
}
然后,根据通过方法传入的条件,将有一个类返回上述类之一:
class ActionPeformerFactory {
// Returns a class which implements the ActionPerformable interface.
public ActionPeformable getInstance(boolean condition) {
if (condition) {
return new ActionPerformerA();
} else {
return new ActionPerformerB();
}
}
}
然后,一个使用上述工厂方法的类,该类根据条件返回适当的实现:
public A getInstance() {
if (condition) {
return new B();
} else {
return new C();
}
}
class Main {
public static void main(String[] args) {
// Factory implementation will return ActionPerformerA
ActionPerformable ap = ActionPerformerFactory.getInstance(true);
// Invokes the action() method of ActionPerformable obtained from Factory.
ap.action();
}
}
但将这种方法放在A
中是一种糟糕的设计A
不应该知道它的子类。工厂方法通常放在不同的类中。@Tadeusz:可能,可能不是。这取决于具体情况。当然,我遇到过这样的情况:父类有一组有限的子类,并且知道它们,认为java枚举模式能够做到这一点。更好的方法是将所有实现都移到另一个类中,并使原始类始终被委托。
class Main {
public static void main(String[] args) {
// Factory implementation will return ActionPerformerA
ActionPerformable ap = ActionPerformerFactory.getInstance(true);
// Invokes the action() method of ActionPerformable obtained from Factory.
ap.action();
}
}