2

我有一个我们称之为Vehicle的抽象类。柴油电动燃气类扩展了车辆。这 3 个类有自己的方法和变量,以及它们从Vehicle继承的内容。

我想将DieselElectricGas对象中的变量放入数据库中的同一个表中。从Electric对象创建的记录只会有几个空列,其中没有与Diesel对象相同的变量,等等。

我想创建插入行、更新行和检索行的方法,所有这些方法都接受来自这些类的对象作为参数。

我正在寻找这个问题的最佳解决方案,因为我认为我不知道它是什么。到目前为止,我能想到一些解决方案,但我不喜欢其中任何一个:

  1. 创建以下每个方法中的 4 个:插入、更新、删除和检索/选择。这将导致大量重复代码。

    public void AddVehicle(Diesel diesel)
    public void AddVehicle(Electric electric)
    public void AddVehicle(Gas gas)
    
    public Electric ViewVehicles()
    public Diesel ViewVehicle()
    public Gas ViewVehicle()
    
    public void RemoveVehicle(Diesel diesel)
    public void RemoveVehicle(Electric electric)
    public void RemoveVehicle(Gas gas)
    
    public void UpdateVehicle(Diesel diesel)
    public void UpdateVehicle(Electric electric)
    public void UpdateVehicle(Gas gas)
    
  2. 创建每个方法以便它可以接受任何对象:(而不是采用任何对象,有没有办法指定它可以采用的对象列表,但仍然只采用其中一个?即。public void AddVehicle(Dieseldiesel | | 电电 || 气气) )

    public void AddVehicle(Object vehicle)
    
    public Object ViewVehicle(Object vehicle)
    
    public void RemoveVehicle(Object vehicle)
    
    public void UpdateVehicle(Object vehicle)
    
  3. 创建一个“主”类,该类可以包含任何类(柴油、电力或燃气),然后将其传递到插入/更新/查看/删除方法中。(将插入/更新/查看方法设置为接受此“主”类作为参数。)“主”类的不完整构造函数:

    public MasterVehicle(Diesel diesel)
    public MasterVehicle(Electric electric)
    public MasterVehicle(Gas gas)
    
  4. 其他一些适当的、更清洁的、更有意义的解决方案。

但是#4可能是什么?

4

5 回答 5

1

我建议将持久层(关系数据库)与面向对象的模型层(Java)分离,忘记“CRUD”操作,更多地考虑对象行为

有一个类Garage实现以下集合会很好Vehicles

interface Garage extends Collection<? extends Vehicle> {
  Vehicle find(int id);
}

然后,您可以像这样使用它:

Garage garage = new GarageInSql(/* your persistence layer details */);
Electric vehicle = Electric.class.cast(garage.find(123));
int mileage = vehicle.mileage();
vehicle.rename("Chevrolet");
garage.remove(vehicle);

如果需要控制交易,再介绍一种方法Garage#commit()

于 2012-12-25T12:15:05.677 回答
1

正如您在问题开始时所说:

我有一个抽象类,我们称之为 Vehicle。柴油、电动和燃气器具类车辆。

因此,Vehicle 是超类,而 Diesel、Electric 和 Gas 是专业。

db 上的表可以反映这种布局

Vehicle (id, brand, price, type) // type could help you selecting electric,gas,diesel

Electric(vehicle_id, volts, amp, ohms, other_specific_stuff)
Gas(vehicle_id, pressure, gas_type, other_specific_stuff) 
Diesel(vehicle_id, other_specific_stuff) 

当您查询您的车辆时,您可以使用左外连接

select * from vehicle as v
    left outer join electric as e on (v.id = e.vehicle_id)
    left outer join gas as g on (v.id = g.vehicle_id)
    left outer join diesel as d on (v.id = d.vehicle_id)

然后使用 type 字段映射到特定的子类。

当您存储或更新数据库中的对象时,您需要一个方法来存储公共部分:

void update(Vehicle v) { 
    // store v.* in Vehicle table
}

以及为特定汽车存储其余部分的方法

void update(Electric e) {
    update(v)
    // store e.* on Electric table
}

删除和插入也是一样。

于 2012-12-24T01:44:34.783 回答
1

幸运的是,其他人也必须处理这个问题:)

你实际上有两个问题。一个是您确定的 API 的设计,另一个是如何处理对 DB 的实际存储/读取。

至于第一个问题,我会选择你的选项#2,因为它最好遵循 OO 设计原则。但我不会让该方法接受Object. 相反,让它接受一个Vehicle类型。

对于第二个问题,您可以查看以下链接:实体继承映射策略。即使您不打算使用 JPA(或任何 ORM 框架),这些也可能是您想要了解的策略。

这里对上面链接中提到的单表策略进行更详细的解释。这应该给你一个好主意 --> 继承:单表策略

于 2012-12-24T01:46:09.183 回答
1

关于您的选择:首先,只要 DieselElectricGas实施/扩展Vehicle ,您就可以拥有Vehicle而不是Object。它应该完成这项工作。

另外对于选项二中的 ViewVehicle :

public Object ViewVehicle(对象车辆)

您可以使用通用方法,以便它始终返回与它相同的类型。更多信息在这里:http ://docs.oracle.com/javase/tutorial/extra/generics/methods.html ...虽然我我不清楚为什么你试图将一个对象发送到一个方法,然后从该方法返回。

于 2012-12-24T01:40:44.067 回答
1

Generic DAO 是您可能感兴趣的内容。尽量避免编写冗长的答案,所以这里是链接。 j-genericdao

您可以在互联网上找到很多通用 dao 的变体。

于 2012-12-24T01:51:47.423 回答