ホームページ >Java >&#&チュートリアル >Javaの複合機構を詳しく解説

Javaの複合機構を詳しく解説

黄舟
黄舟オリジナル
2017-09-09 13:21:171572ブラウズ

この記事では、Java の複合メカニズムの詳細な説明に関する関連情報を主に紹介します。この記事を通じて、誰もが継承と合成の違いを理解し、複合メカニズムを適用できることを願っています。

Java の複合メカニズム 例の詳細な説明

継承の欠陥

継承の欠陥は、その強力すぎる機能によって引き起こされます。この観点から、継承はサブクラスをスーパークラスの実装に依存させます。カプセル化の原則に従いません。
バージョンのリリースによってスーパークラスが変更されると、コードがまったく変更されていない場合でも、サブクラスが壊れる可能性があります。

説明をより具体的にするには、今プログラムで HashSet を使用していると仮定して、この HashSet が作成されてからこの HashSet に追加された要素の数をカウントする関数を追加する必要があります。

継承の欠点を知らずに、クラスを設計し、HashSet を継承し、統計用の属性 addCount を追加し、メソッド内の addCount の値を変更して add メソッドと addAll メソッドをオーバーライドしました。

コードは次のとおりです。


public class InstrumentedHashSet<E> extends HashSet<E> { 
  // The number of attempted element insertions 
  private int addCount = 0; 
 
  public InstrumentedHashSet() { 
  } 
 
  public InstrumentedHashSet(int initCap, float loadFactor) { 
    super(initCap, loadFactor); 
  } 
 
  @Override public boolean add(E e) { 
    addCount++; 
    return super.add(e); 
  } 
 
  @Override public boolean addAll(Collection<? extends E> c) { 
    addCount += c.size(); 
    return super.addAll(c); 
  } 
 
  public int getAddCount() { 
    return addCount; 
  } 
 
}

このクラスは合理的に見えますが、次のコードを実行します:


public static void main(String[] args) { 
  InstrumentedHashSet<String> s = 
    new InstrumentedHashSet<String>(); 
  s.addAll(Arrays.asList("Snap", "Crackle", "Pop"));   
  System.out.println(s.getAddCount()); // expect 3 but 6 
}

3 つの要素しか挿入されていないため、getAddCount メソッドは 3 を返すと予想されます。実際のところ、6 が返されました。何が問題だったのでしょうか?

実際、HashSet 内では、addAll メソッドは add メソッドに基づいて実装されているため、addAll を使用して 3 つの要素を追加すると、addAll が 1 回呼び出され、3 回追加されます。
オーバーライド メソッドを見れば、getAddCount が 6 を返す理由がわかるでしょう。

もちろん、HashSet はこのように実装されているので、addAll メソッドをオーバーライドする必要はない、と言われるでしょう。はい、そうです。

ただし、これは正常に動作しますが、その正しさは、HashSet の addll メソッドが add メソッドに実装されているという事実に依存します。

スーパークラスが実装の詳細を変更すると、関数が影響を受ける可能性があります。

一般に、継承には 3 つの自然な欠陥があり、ソフトウェアが非常に脆弱になります:

1) サブクラスが親クラスのメソッドを呼び出すと、親クラスが呼び出すと、親クラスへの依存関係が形成されます。何も変更しないと、サブクラスが正しく動作しない可能性があります。
2) 親クラスが新しいメソッドを追加し、サブクラスが同じシグネチャで異なる戻り値を持つメソッドをすでに提供している場合、サブクラスはコンパイルできません。
3) 使用すべきでないときに継承を使用すると、不要な API がサブクラスに公開されます。この点で、Java プラットフォームは誤りを犯しています。これは、プロパティ リストがハッシュ テーブルではないのに、結果的にユーザーの後に HashTable を継承するという不合理な例です。 Properties インスタンスを作成します。put メソッドがあります。setProperties と getProperties の 2 つのメソッドは、ユーザーに公開すべきではありません。
プロパティでは、キーと値の両方が文字列である必要がありますが、HashMap は他の型またはオブジェクトである場合もあります。


public class TestProperty { 
  public static void main(String[] args) { 
    Properties properties = new Properties(); 
    properties.setProperty("aaa", "aaa"); 
    properties.put("aaa", new TestPropertyObj()); 
    System.out.println(properties.getProperty("aaa")); // null 
    System.out.println(properties.get("aaa")); // com.hzy.effjava.chp3.item16.TestProperty$TestPropertyObj@5f4fcc96 
  } 
  static class TestPropertyObj { 
     
  } 
}

継承の代替案

前のセクションでは、継承の欠点について説明しました。このセクションでは、この問題の解決策を見てみましょう。

まず、Set オブジェクトを保持するクラスが必要です。このクラスは Set インターフェイスを実装します。実装メソッドは、保持されている Set オブジェクトの対応するメソッドを呼び出すため、これを転送クラスとも呼びます。次に、統計関数を備えたクラスを設計できます。作成したばかりの転送クラスを継承し、統計ロジック コードを記述するだけです。継承を使用しないため、スーパークラスの実装ロジックに依存せず、スーパークラスによって追加された新しいメソッドの影響を心配する必要がありません。

そして、このように書くことにはもう一つ利点があります。このクラスは、HashSet だけでなく、TreeSet などの他の Set も含め、Set インターフェイスを実装するすべてのクラスに統計関数を追加できます。

実際、これは Set を変更し、カウント属性を追加する装飾モードです。

概要


継承によりクラスのカプセル化が破壊され、サブクラスが非常に脆弱で破損しやすくなります。


複合メソッドを使用してスーパークラスを変更し、サブクラスをより堅牢で強力なものにします。

以上がJavaの複合機構を詳しく解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。