簡體   English   中英

Java:Superclass在某些條件下構造子類,可能嗎?

[英]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的對象,否則可以在任何其他條件下替換。

選項1:使用工廠設計模式。

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();

選項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最接近您在問題中直接提出的要求。 但是,我個人會選擇使用工廠設計模式,因為它是更優雅的解決方案,它可以讓你實現你想要做的任何事情。

不直接,沒有。 調用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 ,該方法可以返回BC的實例(假設它們都是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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM