我有这个条件
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"...
这在某种程度上是可能的吗?
答案 0 :(得分:6)
我会说这样做:
this = new B();
A
的构造函数中的会违反OO设计原则,即使有可能(但事实并非如此)。
话虽如此,如果我遇到这种情况:
问题是在我的项目中,超类A已被使用了太多次
我会用以下两种方式之一来解决它:
我假设您的条件是您不需要太多类型A的对象,否则可以在任何其他条件下替换。
public class AFactory
{
private static count = 0;
private static final MAX_COUNT = 100;
public A newObject() {
if (count < MAX_COUNT) {
count++;
return new A();
} else {
return new B();
}
}
}
然后,除此之外,您还可以生成如下对象:
A obj1 = factory.newObject();
A obj2 = factory.newObject();
在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最接近您在问题中直接提出的要求。但是,我个人会选择使用工厂设计模式,因为它是更优雅的解决方案,它可以让你实现你想要做的任何事情。
答案 1 :(得分:5)
不直接,不。调用new A()
将始终创建A
的实例。但是,您可以使A
的构造函数受到保护,然后使用静态方法:
public static A newInstance() {
// Either create A or B here.
}
然后将所有当前调用转换为构造函数以调用工厂方法。
答案 2 :(得分:4)
不可能有条件地控制是否使用超类的构造函数,因为在构造自己的对象之前必须调用其中一个超类构造函数。
从上面可以看出,Java中有一个要求,即构造函数的第一行必须调用超类的构造函数 - 实际上,即使没有对超类构造函数的显式调用,也会有对super()
的隐式调用:
public class X {
public X() {
// ...
}
public X(int i) {
// ...
}
}
public class Y extends X {
public Y() {
// Even if not written, there is actually a call to super() here.
// ...
}
}
应该强调的是,在执行其他操作之后无法调用超类的构造函数:
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.
}
}
也就是说,实现此处所需的方法可能是使用factory method pattern,它可以根据某种条件选择实现类型:
public A getInstance() {
if (condition) {
return new B();
} else {
return new C();
}
}
在上面的代码中,根据condition
,该方法可以返回B
或C
的实例(假设它们都是类A
的子类)。
示例强>
以下是使用interface
而不是class
的具体示例。
让我们有以下接口和类:
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();
}
}
}
然后,使用上述工厂方法的类根据条件返回适当的实现:
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();
}
}
答案 3 :(得分:2)
如果你使用factory method,这是可能的。当你使用构造函数时:nope,完全不可能。
答案 4 :(得分:1)
假设你不愿意将它移动到界面或工厂那么丑陋但是你可以在A中保留B的删除副本并重写你的方法来调用委托:
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
}