[英]Java: Superclass to construct a subclass on certain conditions, possible?
我有這種情況
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"...
這在某種程度上是可能的嗎?
我會說這樣做:
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最接近您在問題中直接提出的要求。 但是,我個人會選擇使用工廠設計模式,因為它是更優雅的解決方案,它可以讓你實現你想要做的任何事情。
不直接,沒有。 調用new A()
將始終創建A
的實例。 但是,您可以使A
的構造函數受到保護,然后使用靜態方法:
public static A newInstance() {
// Either create A or B here.
}
然后將所有當前調用轉換為構造函數以調用factory方法。
不可能有條件地控制是否使用超類的構造函數,因為必須在構造自己的對象之前調用其中一個超類構造函數。
從上面可以看出,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.
}
}
也就是說,實現此處所需的方法可能是使用工廠方法模式 ,它可以根據某種條件選擇實現類型:
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();
}
}
如果您使用工廠方法,這將是可能的。 當你使用構造函數時:nope,完全不可能。
假設你不願意將它移動到界面或工廠那么丑陋但是你可以在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
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.