2016-04-22 3 views
2

車のレンタルシステムの一環として、大型車と小型車を表すクラスを書く必要があります。違いは、サイズの異なるタンクがあり、燃料消費率が異なることです。現在のところ、私のアプローチは、AbstractCarという抽象クラスによって実装されたインタフェースCarを持ち、それは2つの具象クラスSmallCarとLargeCarによって拡張されています。しかし、これはインターフェイスと抽象クラスを使った初めてのことです(私たちはそれらをクラスでカバーしており、この割り当ては私たちの知識を評価するように設計されています)、どのクラスに何を配置するのかを知るのに困っています。インターフェイスと階層を学習し、特定の変数やメソッドを配置する場所は?

fillメソッドの実装はまったく同じです.FUEL_CAPACITYの正しい値を参照するだけでよいので、これらのメソッドをAbstractCarクラスに実装する必要があると感じますが、次に取得する方法はわかりません正しいFUEL_CAPACITY値を参照するようにします。フィールドfuelLevelも明らかにすべての車に保持されているので、AbstractCarで宣言しなければならないと感じますが、プライバシーを削除せずにサブクラスからアクセスすることはできません。

誰でも私が間違っていることやインターフェイスや継承について誤解していることを理解するのに役立つだろうか?私が検討してきたことの1つは、AbstractCarにCarTypeをフィールドとして保持させて、すべての実装がAbstractCarクラスでif文を使用して正しいFUEL_CAPACITY値に切り替え、SmallCarとLargeCarをコンストラクタまたは実際の実装があまりないか、あるいは実際に実装されていないファクトリクラスです。

事前にお手伝いいただきありがとうございます。私は少し長く気付いていますが、私が学んでいるコンセプトを完全に理解していること、そして私が正しく実装していることを確認しようとしています。必ずしも正解であるとは限りません。

+0

ロジックを値で 'AbstractCar'に転送できます。次に、これらの値を 'SmallCar'と' LargeCar'のコンストラクタで設定します。これは1つのアプローチになります。あなたが指摘したように、あなたは常に親クラスに共通ロジックを持たなければなりません。重複するコードを避けたい。次に、コンストラクタで異なる値を設定していることを確認するだけです。そしてもしあなたが修正値を知っていれば、 'SmallCar'または' LargeCar'にパラメータを渡すことを省略して、その固定値をコンストラクタ内の 'super()'呼び出しで設定することさえできます。 –

答えて

1

あなたが指摘したような値でロジックをAbstractCarに転送できます。次に、これらの値をSmallCarとLargeCarのコンストラクタに設定します。これは1つのアプローチになります。あなたが指摘したように、あなたは常に親クラスに共通ロジックを持たなければなりません。重複するコードを避けたい。次に、コンストラクタで異なる値を設定していることを確認するだけです。また、固定値を知っていれば、SmallCarコンストラクタやLargeCarコンストラクタにパラメータを渡すことを省略して、コンストラクタ内のsuper()呼び出しで固定値を設定するだけでも可能です。

私のソリューションの実装は次のとおりです。

アクセスレベルが保護されなければならないので、私はgetFuelMethod()方法除去インターフェースCar

public interface Car { 

    RegistrationNumber getRegistration(); 

    int getFuelCapacity(); 

    // int getFuelLevel(); this can not be implemented 
    // all methods in an interface are PUBLIC 
    // so you have to lower the access level by removing it from the interface 

    // HERE goes the rest of the method signatures 

} 

}

抽象クラスAbstractCar:ここ

public abstract class AbstractCar implements Car { 
    // this is the common variable 
    // that is why we save it in the parent class 
    private int fuelCapacity; 

    private int fuelLevel; 

    // we forward the value to the parent constructor with the super call 
    public AbstractCar(int fuelCapacity) { 
    this.fuelCapacity = fuelCapacity; 
    // I set the value to 0 for the start, but 
    // you can also pass the value to the super call, 
    // same as fuelCapacity - it is up to you 
    this.fuelLevel = 0; 
    } 

    // The getters and setter allow us to retrieve the values 
    // from the abstract class through capsulation! 

    // here we have the getter to be able to retrieve the value from SmallCar and LargeCar 
    public int getFuelCapacity() { 
    return.fuelCapacity; 
    } 

    public void setFuelCapacity(int fuelCapacity) { 
    this.fuelCapacity = fuelCapacity; 
    } 

    protected int getFuelLevel() { 
    return fuelLevel; 
    } 

    protected void setFuelLevel(int fuelLevel) { 
    this.fuelLevel = fuelLevel; 
    } 

    // HERE goes the rest of the code 

} 

でありますSmallCar実装:

public class SmallCar extends AbstractCar { 

    private static final int FUEL_CAPACITY = 45; 

    public SmallCar() { 
    // we set the value in the parent class 
    super(FUEL_CAPACITY); 
    } 

    public int drive() { 
    // HERE goes the logic for drive for SmallCar. Same method is needed 
    // in the LargeCar class, because the logic differes. 
    } 

    // HERE goes the rest of the code 

} 
+0

ありがとう、私はこれは、燃料容量の値が小さいため45、大きな65のために私の状況のた​​めに与えられた最高の答えだと思う。 SMALL_FUEL_CAPACITYとLARGE_FUEL_CAPACITYのどちらかのインタフェースでこれらの定数を宣言するか、具体的なクラスでそれぞれを個別に宣言する方が良いでしょうか? また、私はdrive()の実装が少し違うことに気付きました。したがって、ドライブメソッドは具象クラスで実装する必要がありますが、抽象クラスにあるfuelLevelに書き込む必要もあります。どのようにこの問題を回避するための任意のアイデアですか? もう一度おねがいします! – transiti0nary

+0

燃料容量は定数なので、具体的なクラスで宣言し、コンストラクタで 'super'コールの値を渡すことをお勧めします。 'ドライブ'メソッドに関して、あなたは正しいです。実装が異なるが、依然として同じメソッドシグニチャーがある場合は、抽象クラスで抽象メソッドを宣言することをお勧めします。 –

+0

しかし、私は今インターフェイスでメソッドを宣言しています。これはさらに優れたアプローチです。したがって、あなたは具体的なクラスでこの関数を実装することを義務付けられています - AbstractCarはインスタンス化できません。つまり、 'drive'メソッドを実装する必要はありません。 –

0

あなたの能力は車の唯一のプロパティ(データのみ)の場合、@Jernej K approachを使用しますが、容量を計算すると、一部のロジックを持っている可能性がある場合、これを使用します。

ベストな方法は、抽象メソッドを使用することです。あなたは抽象クラス

public abstract class AbstractCar implements Car { 

    private final RegistrationNumber registration; 
    private boolean isRented; 

    AbstractCar() { 
     this.registration = RegistrationNumber.getInstance(); 
    } 

    public RegistrationNumber getRegistration() { 
     return registration; 
    } 

    public boolean isRented() { 
     return isRented; 
    } 

    //You can use this method in other methods of AbstractCar, but is implemented in your concrete classes 
    public abstract Integer getCapacity(); 

    public boolean isFull() { 
     if (fuelLevel == getCapacity()) { 
      return true; 
     } else return false; 
    } 


} 

abstract Integer getCapacity();にメソッドを配置し、他の機能で使用します。そして、あなたの具体的なクラスでは、あなたがメソッドの本体定義:あなただけのクラスユーザからではなく、さらに開発者からFUEL_CAPACITYを非表示にする場合

public Integer getCapacity(){ 
    //Your logic to calculate capacity for every concrete class here 
} 
+0

もっと良いアプローチは、両方ともその値が必要なので、 'AbstractCar'に値を設定することです。私たちには2人のゲッターがいます。抽象クラスでは実装が可能なので、各クラスのゲッターをオーバーライドする必要はありません。 –

+0

SmallCarとLargeCarに関連するロジックが異なる場合は、オーバーライドを使用します。しかし、彼の例では、修正値は1つしかありません。だから私はあなたのアプローチが殺し過ぎだと思うのです。 –

+0

実際のケースが例と同じなら、このアプローチは過剰ですが、実際のユースケースはより複雑で、コンクリートクラスの他のデータメンバーに基づいて容量を計算または選択するロジックが必要な場合は、これが使用されます。 –

0

を、あなたはAbstractCarprotectedとしてそれを宣言することができますし、子クラスの適切な値で初期化します。また、この値を返すゲッターメソッドgetCapacity()AbstractCarに宣言します。

関連する問題