我有调用相似行为时需要不同参数的Java接口和类实现。以下哪项最合适?
在第一个选项中,我有不同的类从基本接口继承相同的行为,并且所有差异仅在类中直接实现,而不在接口中实现。这似乎最合适,但是我必须在代码中进行手动类型转换。
public class VaryParam1 {
static Map<VehicleType, Vehicle> list = new HashMap<>();
static List<Car> carsList = new ArrayList<>();
static List<TruckWithTrailer> trucksList = new ArrayList<>();
public static void main(String[] args) {
list.put(VehicleType.WITHOUT_TRAILER, new Car());
list.put(VehicleType.WITH_TRAILER, new TruckWithTrailer());
//violates LSP?
((Car)list.get(VehicleType.WITHOUT_TRAILER)).paint(1); //ok - but needed manual cast
((TruckWithTrailer)list.get(VehicleType.WITH_TRAILER)).paint(1, "1"); //ok - but needed manual cast
carsList.add(new Car());
trucksList.add(new TruckWithTrailer());
//Does not violate LSP
carsList.get(0).paint(1);
trucksList.get(0).paint(1, "1");
}
}
enum VehicleType {
WITHOUT_TRAILER,
WITH_TRAILER;
}
interface Vehicle{
//definition of all common methods
void drive();
void stop();
}
class Car implements Vehicle {
public void paint(int vehicleColor) {
System.out.println(vehicleColor);
}
@Override
public void drive() {}
@Override
public void stop() {}
}
class TruckWithTrailer implements Vehicle {
public void paint(int vehicleColor, String trailerColor) {
System.out.println(vehicleColor + trailerColor);
}
@Override
public void drive() {}
@Override
public void stop() {}
}
在第二个选项中,我将方法上移到接口的上一级,但是现在我需要使用UnsupportedOpException实现行为。这看起来像代码气味。在代码中,我不必手动进行强制转换,但是我也有可能调用在运行时会产生异常的方法,而无需进行编译时检查。这不是什么大问题-只有这种看起来像代码气味的异常方法。这种实施方式是最佳实践吗?
public class VaryParam2 {
static Map<VehicleType, Vehicle> list = new HashMap<>();
public static void main(String[] args) {
list.put(VehicleType.WITHOUT_TRAILER, new Car());
list.put(VehicleType.WITH_TRAILER, new TruckWithTrailer());
list.get(VehicleType.WITHOUT_TRAILER).paint(1); //works
list.get(VehicleType.WITH_TRAILER).paint(1, "1"); //works
list.get(VehicleType.WITHOUT_TRAILER).paint(1, "1"); //ok - exception - passing trailer when no trailer - no compile time check!
list.get(VehicleType.WITH_TRAILER).paint(1); //ok - exception - calling trailer without trailer args - no compile time check!
}
}
enum VehicleType {
WITHOUT_TRAILER,
WITH_TRAILER;
}
interface Vehicle{
void paint(int vehicleColor);
void paint(int vehicleColor, String trailerColor); //code smell - not valid for all vehicles??
}
class Car implements Vehicle {
@Override
public void paint(int vehicleColor) {
System.out.println(vehicleColor);
}
@Override
public void paint(int vehicleColor, String trailerColor) { //code smell ??
throw new UnsupportedOperationException("Car has no trailer");
}
}
class TruckWithTrailer implements Vehicle {
@Override
public void paint(int vehicleColor) { //code smell ??
throw new UnsupportedOperationException("What to do with the trailer?");
}
@Override
public void paint(int vehicleColor, String trailerColor) {
System.out.println(vehicleColor + trailerColor);
}
}
在这里,我使用泛型以便在接口中具有通用方法,并且在每个类的实现中确定参数类型。这里的问题是我未选中绘画请求。这更类似于选项1中的直接转换问题。Bur在这里,我也有可能调用我不应该使用的方法!
public class VaryParam3 {
static Map<VehicleType, Vehicle> list = new HashMap<>();
public static void main(String[] args) {
list.put(VehicleType.WITHOUT_TRAILER, new Car());
list.put(VehicleType.WITH_TRAILER, new TruckWithTrailer());
list.get(VehicleType.WITHOUT_TRAILER).paint(new VehicleParam()); //works but unchecked call
list.get(VehicleType.WITH_TRAILER).paint(new TruckWithTrailerParam()); //works but unchecked call
list.get(VehicleType.WITHOUT_TRAILER).paint(new TruckWithTrailerParam()); //works but should not!
list.get(VehicleType.WITH_TRAILER).paint(new VehicleParam()); //ClassCastException in runtime - ok but no compile time check
}
}
enum VehicleType {
WITHOUT_TRAILER,
WITH_TRAILER;
}
class VehicleParam {
int vehicleColor;
}
class TruckWithTrailerParam extends VehicleParam {
String trailerColor;
}
interface Vehicle<T extends VehicleParam>{
void paint(T param);
}
class Car implements Vehicle<VehicleParam> {
@Override
public void paint(VehicleParam param) {
System.out.println(param.vehicleColor);
}
}
class TruckWithTrailer implements Vehicle<TruckWithTrailerParam> {
@Override
public void paint(TruckWithTrailerParam param) {
System.out.println(param.vehicleColor + param.trailerColor);
}
}
所以问题是-这3个选项中哪一个是最好的(或者是否还有我找不到的其他选项)?在进一步维护,更改等方面
更新
我更新了问题,现在有了paint方法,只有在构造对象之后才能调用它。
到目前为止,这似乎是最好的选择,如以下文章中所建议:
public class VaryParam4 {
static Map<VehicleType, Vehicle> list = new HashMap<>();
public static void main(String[] args) {
list.put(VehicleType.WITHOUT_TRAILER, new Car());
list.put(VehicleType.WITH_TRAILER, new TruckWithTrailer());
list.get(VehicleType.WITHOUT_TRAILER).paint(new PaintConfigObject()); //works but can pass trailerColor (even if null) that is not needed
list.get(VehicleType.WITH_TRAILER).paint(new PaintConfigObject()); //works
}
}
enum VehicleType {
WITHOUT_TRAILER,
WITH_TRAILER;
}
class PaintConfigObject {
int vehicleColor;
String trailerColor;
}
interface Vehicle{
void paint(PaintConfigObject param);
}
class Car implements Vehicle {
@Override
public void paint(PaintConfigObject param) {
//param.trailerColor will never be used here but it's passed in param
System.out.println(param.vehicleColor);
}
}
class TruckWithTrailer implements Vehicle {
@Override
public void paint(PaintConfigObject param) {
System.out.println(param.vehicleColor + param.trailerColor);
}
}
更好的选择是摆脱方法的重载版本,drive
并传递构造函数中子类所需的所有信息:
interface Vehicle{
void drive();
}
class Car implements Vehicle {
private int numberOfDoors;
public Car(int numberOfDoors) {
this.numberOfDoors = numberOfDoors;
}
public void drive() {
System.out.println(numberOfDoors);
}
}
class TruckWithTrailer implements Vehicle {
private int numberOfDoors;
private int numberOfTrailers;
public TruckWithTrailer(int numberOfDoors,numberOfTrailers) {
this.numberOfDoors = numberOfDoors;
this.numberOfTrailers = numberOfTrailers;
}
@Override
public void drive() {
System.out.println(numberOfDoors + numberOfTrailers);
}
}
解决您关于paint
在运行时确定问题的评论,您可以paint
向车辆添加一个采用可变参数的方法:
interface Vehicle{
void drive();
void paint(String ...colors);
}
如评论中所述,如果在paint方法中使用的参数数量因不同的车辆类型而异,则定义一个名为的类PaintSpecification
,其中包含诸如之类的属性vehcileColor
,trailerColor
然后将paint
方法更改为具有type的参数PaintSpecification
。
interface Vehicle{
void drive();
void paint(PaintSpecification spec);
}
上述所有方法的优点在于,所有Vehicle
实现都遵循一个协定,从而使您可以执行操作,例如将所有Vehicle
实例添加到,List
并paint
对其一个一个地调用它们的方法,而不管它们的类型如何。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句