我有一堆无法更改的类;所有这些类都有一个共同的祖先(而不是Object),它声明并实现了它们的大部分属性和方法。
比方说,我们有一个这样的继承树(仅用于说明):
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 %sn",aClass.toString());
Constructor c;
try
{
c=aClass.getConstructor();
}
catch(NoSuchMethodException e)
{
System.out.format(" no constructor foundn");
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 %sn",
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
这听起来很像工厂模式,所以您可能需要对此进行研究。
你基本上会做这样的事情:
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());
最后一部分也将预先确定使用因子或构建器模式。
当子类不能完全填充构造函数与父类的契约时。然后在同一个地方存在一个设计缺陷。
问题/原因可能是子类作为子类无效,或者父类具有许多功能。
以你为例,很难判断什么是违反合同的。但最好和最灵活的工作方式是接口。
您声称自己不是Java方面的专家。接口只是面向对象编程中的一个概念,如果你在这个领域寻找任何载体,你应该熟悉它们。因此,这可能是你学习更多关于接口和软件设计的时候了。