2012-04-17 20 views
1

私はJava OOPの問題に悩まされています。私は問題を説明するために、いくつかのおもちゃのコードを思いついた。 1Java OOPの問題 - インタフェース/抽象クラスに関連する

クラス - - 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'が渡されます。いくつかのOOPテクニックを使用して、2つのメソッド呼び出し(setNameとsetNumWheels)を実行する方法がありますか?reportProblemが呼び出される前に?

私は自分自身を明確にしたいと思います。私がそうでないならば、私はあなたがそれをどのようにして、それから学ぶことができるかを教えてください。 「必要」

答えて

6

はい、最終的にnamenumWheelsとし、コンストラクタに割り当てます。だから... ...

クラス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彼らはCLASのユーザーによって変更することができ、あなたのクラスの実装の詳細を公開するためのフィールドは、良いオブジェクト指向の練習ではありませんs。これらのフィールドはprivateである必要があります。クラスのクライアントがそれらについて知る必要がある場合(または変更する場合)は、パブリックゲッター(またはセッター)メソッドを許可する必要があります。

+0

ありがとう!これはcarのコンストラクタからsuper.mName = "Car"を実行するよりはるかに優れています!これは私が欲しかったものです。 mNameとmNumWheelsはVehicleでプライベートにする必要があると思います。 – MediumOne

+0

正しい。私はあなたが持っていたものをコピーしました。私のポストの最後のステートメントに注目してください。 –

+0

ああああ!さっき気付いた。ありがとう! – MediumOne

1

あなたがフィールドを設定する場合は、これらのクラスのデフォルトコンストラクタを提供するトラック/カーコンストラクタのパラメータとしてそれらを設定し、することはできません。

+0

プライベートデフォルトコンストラクタのポイントは何ですか?なぜそれを含めるだけではないのですか?通常、プライベートコンストラクタは、静的ファクトリメソッドを持つクラスでのみ使用するか、スタティックメソッドのみを持つユーティリティクラスにのみ使用し、インスタンスを作成する必要はありません。 –

+0

ありがとう!わかった!私はトラック/車のコントラクターの名前とnumWheelsを割り当てました!さて、私はTest.javaで再度設定する必要はありません。実際には、ビークルでsetメソッド(setNameとsetNumWheels)を必要としません!しかし、なぜ私はそれらを私的にする必要があるのか​​分かりません。 – MediumOne

+0

@ MediumOneクラスの実装を公開するのは貧弱なOOの慣習と見なされます。これにはフィールドへのアクセスも含まれます。このケースは一般的に2つのステートメントです。まず、インプリメンテーションのフィールド名を変更する(intを整数に変更するなど)場合は、ユーザーに影響を与えたくありません。アクセスがゲッターメソッドに限定されていると、影響はより限定的です。次に、セッターを介してフィールドの操作を制御できるようにして、検証を許可します(何かがnullに設定されていないことを確認します)。つまり、「公的最終決定」は安全だが良い練習ではないという。 –

0

メンバがオブジェクトの状態/機能にとって不可欠な場合は、メンバをコンストラクタの一部として配置するため、メンバに適切な値を指定せずにオブジェクトを作成(および関心のあるメソッドを呼び出す)することはできません。
しかし、引数なしのコンストラクタも提供しないでください。あなたは豆表記(デフォルトコンストラクタとセッター)を使用する必要があり、まだ使用して許可したくない場合は
必要あまりにも多くのパラメータがある場合には、トニーの回答(1)@に加えてビルダーidion

+0

私は多くのパラメータを持っています。ですから、Builderパターンを使用する以外の方法はありませんか? – MediumOne

+1

オブジェクトを適切にチェックアウトする必要がある場合http://rwhansen.blogspot.com/2007/07/theres-builder-pattern-that-joshua.html – Cratylus

0

に探して検討しますオブジェクトが初期化される前のビジネスメソッドは、以下を実行できます。

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

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

このテクニックは少し冗長です。おそらく、ラッパーパターンまたはAOP(例えば、AspectJ)を使用することが有用であり得る。

関連する問題