1

我被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”的实现)。但我知道这不是最好的方法。一个原因是不应该调用“reportProblem”方法而不调用“setName”和“setNumWheels”方法。否则将传递“null”。有没有一种方法可以在调用 reportProblem 之前使用一些 OOP 技术来执行两种方法调用(setName 和 setNumWheels)?

我希望我已经说清楚了。如果我不是,请告诉我你会怎么做,这样我就可以从中学习。

4

4 回答 4

6

是的,在构造函数中 makenamenumWheelsfinal 并赋值。所以...

第 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)方法。

于 2012-04-17T12:09:04.553 回答
1

如果要设置“必填”字段,可以将它们设置为 Truck/Car 构造函数中的参数,并且不为这些类提供默认构造函数。

于 2012-04-17T12:07:49.980 回答
0

如果成员是对象状态/功能的必需品,请将它们作为构造函数的一部分,因此如果不为这些成员提供适当的值,就不可能创建对象(并调用相关方法)。
但是您也不应该提供无参数构造函数。
如果需要太多参数,请考虑查看 Builder idion

于 2012-04-17T12:15:42.600 回答
0

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

checkInitalized()在您的Vehicle类中定义抽象方法。Car为您的和实现此方法Truck。顺便说一句,此方法可能会在Vehicle. 在这种情况下,不要忘记从其覆盖的版本中调用 super。

checkInitalized()IllegalStateException如果未初始化所有必需字段,则应抛出异常(例如)。现在在每个业务方法的开头调用这个方法。这将阻止您使用尚未初始化的对象。

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

于 2012-04-17T12:15:56.140 回答