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」の実装を抽象化しました)。しかし、これが最善の方法ではないことはわかっています。理由の 1 つは、「setName」および「setNumWheels」メソッドを呼び出さずに「reportProblem」メソッドを呼び出すべきではないことです。それ以外の場合は「null」が渡されます。reportProblem が呼び出される前に、何らかの OOP 手法を使用して、2 つのメソッド呼び出し (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

フィールドを「必須」に設定する場合は、トラック/車のコンストラクターでパラメーターとして設定し、これらのクラスにデフォルトのコンストラクターを提供しないようにすることができます。

于 2012-04-17T12:07:49.980 に答える
0

メンバーがオブジェクトの状態/機能に不可欠な場合は、それらをコンストラクターの一部として配置するため、これらのメンバーに適切な値を提供せずにオブジェクトを作成する (および関連するメソッドを呼び出す) ことはできません。
ただし、引数なしのコンストラクターも提供しないでください。
必要なパラメーターが多すぎる場合は、Builder idion を調べることを検討してください

于 2012-04-17T12:15:42.600 に答える
0

@Tony の回答 (+1) に加えて、Bean 表記 (デフォルトのコンストラクターとセッター) を使用する必要があり、オブジェクトが初期化される前にビジネスメソッドの使用を許可したくない場合は、次のことができます。

クラスで抽象メソッドを定義checkInitalized()しますVehicleCarこのメソッドをとに実装しますTruck。ところで、このメソッドはおそらくデフォルトで実装されVehicleます。この場合、オーバーライドされたバージョンから super を呼び出すことを忘れないでください。

checkInitalized()IllegalStateExceptionすべての必須フィールドが初期化されていない場合は、例外 (例: ) をスローする必要があります。ここで、各ビジネス メソッドの先頭でこのメソッドを呼び出します。これにより、まだ初期化されていないオブジェクトを使用できなくなります。

この手法は少し冗長です。ここではおそらくラッパー パターンまたは AOP (AspectJ など) を使用すると便利です。

于 2012-04-17T12:15:56.140 に答える