Java OOP问题 - 与接口/抽象类相关

时间:2012-04-17 12:03:44

标签: java oop

我遇到了Java OOP问题。我想出了一些玩具代码来解释这个问题。这是我的课程 -

第1类 - Car.java

public class Car {

    public void reportProblem(String problem){
        ReportUtil.reportVehicleInfo("Car", 4, problem); //4 is number of wheels
    }

    //bunch of other methods
}

第2类 - Truck.java

public class Truck {
    public void reportProblem(String problem){
        ReportUtil.reportVehicleInfo("Truck", 6, problem);
    }

    //bunch of other methods
}

第3类 - ReportUtil.java

public class ReportUtil {
    public static void reportVehicleInfo(String name, int wheels, String problem){
        System.out.println(String.format("%s %s %s", name, wheels, problem));
    }
}

第4类 - Test.java

public class Test {
    public static void main(String[] args) {
        Car c = new Car();
        c.reportProblem("puncture");

        Truck t = new Truck();
        t.reportProblem("engine missing");
    }
}

我想将“Car”和“Truck”中的“reportProblem”方法实现抽象为父类。这就是我做的 -

第1类 - Vehicle.java

public abstract class Vehicle {
    public String mName;
    public int mNumWheels;

    public void reportProblem(String problem){
        ReportUtil.reportVehicleInfo(mName, mNumWheels, problem);
    }

    public void setName(String name){
        mName = name;
    }

    public void setNumWheels(int numWheels){
        mNumWheels=numWheels;
    }
}

第2类 - Car.java

public class Car extends Vehicle {

    //bunch of other methods
}

第3类 - Truck.java

public class Truck extends Vehicle {

    //bunch of other methods
}

第4类 - ReportUtil.java(对此类没有任何更改)。

public class ReportUtil {   
    public static void reportVehicleInfo(String name, int wheels, String problem){
        System.out.println(String.format("%s %s %s", name, wheels, problem));
    }
}

第5类 - Test.java

public class Test {
    public static void main(String[] args) {
        Car c = new Car();
        c.setName("Car"); //NOTE : Can be missed!
        c.setNumWheels(4); //NOTE : Can be missed!
        c.reportProblem("puncture");

        Truck t = new Truck();
        t.setName("Truck"); //NOTE : Can be missed!
        t.setNumWheels(6); //NOTE : Can be missed!
        t.reportProblem("engine missing");
    }
}

这实现了我想要的东西(我已经抽象了“reportProblem”的实现)。但我知道这不是最好的方法。一个原因是,如果不调用“setName”和“setNumWheels”方法,则不应调用“reportProblem”方法。否则将传递'null'。有没有一种方法可以使用一些OOP技术在调用reportProblem之前调用两个方法调用(setName和setNumWheels)?

我希望我已经说清楚了。如果我不是,请告诉我你将如何做到这一点,以便我可以从中学习。

4 个答案:

答案 0 :(得分:6)

是的,将namenumWheels设为final,然后在构造函数中指定。所以......

第1类 - Vehicle.java

public abstract class Vehicle {
  public final String mName;
  public final int mNumWheels;

  protected Vehicle(String name, int numWheels){
    this.mName = name;
    this.mNumWheels = numWheels;
  }

  public void reportProblem(String problem){
    ReportUtil.reportVehicleInfo(mName, mNumWheels, problem);
  }
  ...
}

第2类 - Car.java

public class Car extends Vehicle {

   public Car(){
     super("Car", 4);
   }
 //bunch of other methods
}

第3类 - Truck.java

public class Truck extends Vehicle {

   public Truck(){
     super("Truck", 6);
   }
//bunch of other methods
}

此外,public字段不是良好的OO实践,因为它们公开了类的实现的细节,可以由类的用户修改。这些字段应为private。如果类的客户需要知道它们(或更改它们),那么你应该允许公共getter(或setter)方法。

答案 1 :(得分:1)

如果要设置“required”字段,可以在Truck / Car构造函数中将它们设置为参数,而不是为这些类提供默认构造函数。

答案 2 :(得分:0)

如果成员是对象状态/功能的基本要素,则将它们作为构造函数的一部分,因此无法为这些成员提供适当的值而无法创建对象(并调用关注的方法)。
但是你不应该提供一个no-args构造函数 如果需要太多参数,请考虑查看Builder idion

答案 3 :(得分:0)

除了@Tony的答案(+1),如果你必须使用bean表示法(默认构造函数和setter),并且仍然不希望在初始化对象之前允许使用任何业务方法,你可以执行以下操作。 p>

checkInitalized()课程中定义抽象方法Vehicle。为您的CarTruck实施此方法。顺便说一句,这个方法可能会在Vehicle中有默认实现。在这种情况下,不要忘记从被覆盖的版本调用super。

如果未初始化所有必填字段,则

checkInitalized()应抛出异常(例如IllegalStateException)。 现在在每个业务方法的开头调用此方法。这将阻止您使用尚未初始化的对象。

这种技术有点冗长。可能在这里使用包装器模式或AOP(例如AspectJ)可能是有用的。