2014-04-15 29 views
-1

我有一堆我不能改變的類;所有這些類都有一個共同的祖先(Object除外),這些祖先聲明並實現了它們的大部分屬性和方法。帶有不兼容構造函數的java繼承

比方說,我們有一個繼承樹像這樣(只用於說明目的):

class Vehicle 
    class Bicycle extends Vehicle 
    class Skateboard extends Vehicle 
    class Boat extends Vehicle 
    class Car extends Vehicle 
    class Aircraft extends Vehicle 
     class Jetplane extends Aircraft 
     class Helicopter extends Aircraft 
     ... 
    class Truck extends Vehicle 
    ... 

雖然class Vehicle其實更像是一個抽象類(它是不是真的,但它永遠不會實例自身代表),偶爾會創建class Aircraft的對象。

現在的觀點:對象可以有不反映類的相互關係。由於它是相當一類的類,並且集合每隔一段時間都會改變,所以爲實現缺失行爲的每個類維護一個子類是不實際的。

因此,我的方法是讓一個類用作上述類的包裝。 構造函數將相應對象的類作爲參數,然後使用反射對其進行實例化。

class VehicleW 
{ 
    // fields 
    public boolean isInitialized=false; 
    private Vehicle fVehicle; 
    ... 

    // constructors 
    public VehicleW(Class aClass, ...) 
    { 
    Class VehicleClass = Vehicle.class; 
    if (!VehicleClass.isAssignableFrom(aClass)) 
     return; 

    // <the reflection magic here> 
    ... 
    // and on success mark this object as usable 
    isInitialized=true; 
    } 
} 

沒有參數的構造函數在這裏沒有意義。但現在class Aircraft及其子類想要一些額外的屬性,所以我想我可以建立一個class AircraftW extends VehicleW照顧他們。

然後修改如下:

// fields 
    private Aircraft fAircraft; 

    // constructors 
    public AircraftW(Class aClass, ...) 
    { 
    Class AircraftClass = AirCraft.class; 
    if (!AircraftClass.isAssignableFrom(aClass)) 
     return; 

    // <the reflection magic here> 
    ... 
    // and on success mark this object as usable 
    isInitialized=true; 
    } 

但這種失敗,因爲Java智能插入的祖先,這是不存在的參數的構造函數的調用(和沒有意義,因爲已經說過)。

調用參數化的super()也沒有意義,因爲我初始化了class Vehicle的字段。好的,我稍後可以在AircraftW()中將該字段設置爲null,但這看起來不正確。

有沒有辦法解決這個問題?或者我正在採取絕對錯誤的方法?我想過泛型,但我似乎無法找到使用它的一點。接口?我不是一個Java專家,所以任何建議都是值得歡迎的。

編輯(未解決的(避免解決)術語好了,下面你找到一個工作程序。我不能把它作爲答案,因爲托馬斯帶領我去了這個代碼......他的答案......我接受了這個解決方案......我看不出有什麼問題。

謝謝,托馬斯,指出我在正確的方向。

對於持懷疑態度,這裏的完整源的測試程序的代碼:

import java.lang.reflect.Constructor; 
import java.lang.reflect.InvocationTargetException; 

class Vehicle { public Vehicle(){} } 
class Bicycle extends Vehicle { public Bicycle(){} } 
class Skateboard extends Vehicle { public Skateboard(){} } 
class Boat extends Vehicle { public Boat(){} } 
class Car extends Vehicle { public Car(){} } 
class Aircraft extends Vehicle { public Aircraft(){} } 
class Jetplane extends Aircraft { public Jetplane(){} } 
class Helicopter extends Aircraft { public Helicopter(){} } 
class Truck extends Vehicle { public Truck(){} } 

class VehicleW 
{ 
    protected Vehicle fVehicle=null; 
    public boolean isInitialized=false; 

    public VehicleW(Class aClass) 
    { 
    if (checkVehicle(aClass)) 
     if ((fVehicle=makeVehicle(aClass))!=null) 
     isInitialized=true; 
    } 

    protected boolean checkVehicle(Class aClass) 
    { 
    Class tClass = Vehicle.class; 
    return (tClass.isAssignableFrom(aClass)); 
    } 

    protected Vehicle makeVehicle(Class aClass) 
    { 
    Vehicle tVehicle = null; 

    System.out.format("trying to create %s\n",aClass.toString()); 

    Constructor c; 

    try 
    { 
     c=aClass.getConstructor(); 
    } 
    catch(NoSuchMethodException e) 
    { 
     System.out.format(" no constructor found\n"); 
     return null; 
    } 

    try 
    { 
     tVehicle=(Vehicle)c.newInstance(); 
    } 
    catch(InvocationTargetException e) 
    { 
     System.out.println(e.toString()); 
    } 
    catch(InstantiationException e) 
    { 
     System.out.println(e.toString()); 
    } 
    catch(IllegalAccessException e) 
    { 
     System.out.println(e.toString()); 
    } 
    return tVehicle; 
    } 

    public Vehicle getVehicle() 
    { 
    if (!isInitialized) 
     return null; 
    return fVehicle; 
    } 
    public Class getWClass() 
    { 
    if (!isInitialized) 
     return null; 
    return fVehicle.getClass(); 
    } 
} 

class AircraftW extends VehicleW 
{ 
    public AircraftW(Class aClass) 
    { 
    super(aClass); 
    /* 
    Class tClass=Aircraft.class; 
    if (!tClass.isAssignableFrom(aClass)) 
     return; 
    isInitialized=true; 
    */ 
    } 

    @Override 
    protected boolean checkVehicle(Class aClass) 
    { 
    Class tClass = Aircraft.class; 
    return (tClass.isAssignableFrom(aClass)); 
    } 
} 

class program 
{ 
    public static void tellme(VehicleW vx) 
    { 
    String s = "failed"; 
    if (vx.getVehicle()!=null) 
     s="succeeded"; 
    System.out.format(" making %s for %s %s\n", 
         vx.getWClass(),vx.getClass(),s); 
    } 

    public static void main(String[] args) 
    { 
    VehicleW v1, v2, v3; 
    AircraftW a1, a2, a3; 

    v1=new VehicleW(Bicycle.class); 
    tellme(v1); 
    v2=new VehicleW(Boat.class); 
    tellme(v2); 
    v3=new VehicleW(Helicopter.class); 
    tellme(v3); 

    a1=new AircraftW(Helicopter.class); 
    tellme(a1); 
    a2=new AircraftW(Aircraft.class); 
    tellme(a2); 
    a3=new AircraftW(Truck.class); 
    tellme(a3); 

    return; 
    } 
} 

和輸出:

trying to create class Bicycle 
    making class Bicycle for class VehicleW succeeded 
trying to create class Boat 
    making class Boat for class VehicleW succeeded 
trying to create class Helicopter 
    making class Helicopter for class VehicleW succeeded 
trying to create class Helicopter 
    making class Helicopter for class AircraftW succeeded 
trying to create class Aircraft 
    making class Aircraft for class AircraftW succeeded 
    making null for class AircraftW failed 
+0

這種類型的問題的問題是,如果沒有更多關於你正在構建的系統試圖實現什麼的知識很難提出合適的設計(甚至在某種程度上它會是意見)。我想說的是,如果你的構造函數在繼承層次結構中是「不兼容的」,那麼應該告訴你繼承不是用於你正在建模的實體的正確技術 –

+0

不要編輯你的問題到包括單詞*(已解決)*。在下面添加自己的答案,然後將該答案標記爲已接受,以便系統將問題標記爲綠色。 –

回答

0

這聽起來很像工廠模式,所以你可能想看看。

基本上你會怎麼做,是這樣的:

class VehicleFactory { 
    public static Vehicle createAircraft(/*Aircraft specific parameters*/) { 
    //build and return Aircraft, you can call your reflection magic here 
    } 

    public static Vehicle createBoat(/*Boatspecific parameters*/) { 
    //build and return Boat, you can call your reflection magic here 
    } 
} 

此外,你可能要考慮生成器模式。

在你的方法有幾個問題:

  • 從構造函數返回過早仍然保持創建的對象,它可能只是無法正確初始化(您使用的是屬性信號完全初始化但什麼除了刪除它們之外,你還會使用未初始化的對象嗎?在這種情況下,initialized不應該是對象或包裝器本身的屬性)。
  • 如果你有這麼多的子類,你可能想要檢查它們之間的差異。這可能是一種更靈活的方法來使用組合而不是繼承。最後一點的

實施例:

class Vehicle { 
    VehicleType type; //e.g. Aircraft, Boat, Car 
    Set<Features> features; //e.g. 2 wheels, 4 wheels, wings etc. 
    Behavior behavior; //Class to implement specific behavior, depending on your needs 
} 

class AircraftBehavior extends Behavior { 
    void fly() { 
    //implements flying mechanic 
    } 

    //method overridden/implemented from Behavior 
    @Override 
    void move() { 
    fly(); 
    } 
} 

//create an aircraft 
Vehicle aircraft = new Vehicle(VehicleType.AIRCRAFT, new HashSet<Feature>(new WingsFeature()), new AircraftBehavior()); 

最後部分也將被註定用於使用所述因數或助洗劑圖案。

+0

我除了丟棄它們之外沒有對這些對象做任何事情。但是看到一個對象可能不能以這種方式創建,而不是涉及異常和相應的處理程序(或只是看到整個應用程序死掉)。 ---我會尋找工廠模式。 – user3536191

+0

關於這個構圖的例子:不幸的是,我對'class Vehicle'及其後代沒有任何影響......如果我有,我根本沒有發現任何問題。 – user3536191

0

當孩子上課不能完全填補構造的合同,父類。然後在同一個地方存在設計缺陷。

問題/原因可能是子類無法用作子類,或者父類有許多功能。

舉個例子,很難說什麼是違約。但最好和最靈活的工作是接口。

你聲稱你不是Java的專家。接口只是面向對象編程中的一個概念,如果你在這個領域尋找任何載體,你應該熟悉它們。所以這可能是您瞭解更多關於接口和軟件設計的時候了。

+0

最佳的解決方案是修改類的集合,但這是不可能的。我也考慮過接口,但我不明白他們在這裏可以提供什麼幫助。問題僅在於創建包裝對象。當我實現'class AircraftW'的構造函數以允許'Vehicle.class'傳遞時,其餘的都沒問題。但這樣我沒有一致性檢查。 – user3536191