「労働者が自分の仕事をうまくやりたいなら、まず自分の道具を研ぎ澄まさなければなりません。」 - 孔子、「論語。陸霊公」
表紙 > プログラミング > 構成と継承

構成と継承

2024 年 11 月 9 日に公開
ブラウズ:438

Composición vs Herencia

導入

継承と合成はオブジェクト指向プログラミング (OOP) の 2 つの基本概念ですが、使用方法も目的も異なります。この投稿の目的は、これらの目的と、それらを選択する際に留意すべき点を確認することです。

継承の概念

設計に継承を適用​​することを考えるとき、次のことを理解する必要があります。

  • 定義: 継承では、クラス (派生クラスまたはサブクラスと呼ばれます) は、別のクラス (基本クラスまたはスーパークラスと呼ばれます) からプロパティと動作を継承できます。派生クラスは、基本クラスの機能を拡張または変更できます。
  • 関係: 「である」(is-a) という関係です。たとえば、クラス「Vehicle」と別のクラス「Car」がある場合、クラス「Car」は「Vehicle」のサブクラスになります。
  • 利点: コードの再利用が促進され、機能を簡単に拡張できます。

構成の概念

一方、オブジェクトを一緒に構成することを考えると次のようになります。

  • 定義: 合成では、オブジェクトは他のオブジェクトを含み、その機能の一部をそれらのオブジェクトに委任します。クラスは継承の代わりに、他のクラスのインスタンスを使用してその機能を実現します。
  • 関係: これは「ある」関係です。たとえば、クラス「Engine」とクラス「Car」がある場合、クラス「Car」はクラス「Engine」のオブジェクトを持つことができます。
  • 利点: 柔軟性が向上し、クラス間の結合が少なくなります。一方のクラスの変更は、もう一方のクラスには直接影響しません。

なぜ継承に基づいて合成するのでしょうか?

合成が継承よりも優れているのか、それともその逆なのかという問題は、ソフトウェア設計において議論の対象となっています。どちらのアプローチにも長所と短所があり、選択は特定のプロジェクトのコンテキストと要件によって異なります。ここでは、継承より合成の方が望ましい例を紹介します。

Java の例を見て、特定の場合に継承よりも合成の方がどのように優先されるかを説明します。オンライン ストアの注文処理システムに取り組んでいるとします。

  • 継承アプローチ:

まず、継承を使用して書籍や電子機器などのさまざまな種類の購入可能な商品を表すアプローチを考えてみましょう。

// Clase base para productos
class Producto {
    String nombre;
    double precio;

    Producto(String nombre, double precio) {
        this.nombre = nombre;
        this.precio = precio;
    }

    void procesarPedido() {
        System.out.println("Procesando pedido para "   nombre);
    }
}

// Clase para productos electrónicos que hereda de Producto
class ProductoElectronico extends Producto {
    String modelo;

    ProductoElectronico(String nombre, double precio, String modelo) {
        super(nombre, precio);
        this.modelo = modelo;
    }
}

// Clase para libros que hereda de Producto
class Libro extends Producto {
    String autor;

    Libro(String nombre, double precio, String autor) {
        super(nombre, precio);
        this.autor = autor;
    }
}

このアプローチは機能しますが、新しい製品タイプを導入したり、特定の製品タイプに特定の機能を追加したりする必要がある場合はどうすればよいですか?

  • 構図でフォーカス:

継承に完全に依存する代わりに、合成を使用してさまざまなタイプの製品をより柔軟に処理できます。

// Clase para productos
class Producto {
    String nombre;
    double precio;

    Producto(String nombre, double precio) {
        this.nombre = nombre;
        this.precio = precio;
    }

    void procesarPedido() {
        System.out.println("Procesando pedido para "   nombre);
    }
}

// Clase para productos electrónicos que utiliza composición
class ProductoElectronico {
    Producto producto;
    String modelo;

    ProductoElectronico(String nombre, double precio, String modelo) {
        this.producto = new Producto(nombre, precio);
        this.modelo = modelo;
    }

    // Puedes agregar lógica específica para productos electrónicos si es necesario
    void procesarPedidoEspecifico() {
        System.out.println("Procesando pedido específico para "   producto.nombre);
    }
}

// Clase para libros que utiliza composición
class Libro {
    Producto producto;
    String autor;

    Libro(String nombre, double precio, String autor) {
        this.producto = new Producto(nombre, precio);
        this.autor = autor;
    }

    // Puedes agregar lógica específica para libros si es necesario
    void procesarPedidoEspecifico() {
        System.out.println("Procesando pedido específico para "   producto.nombre);
    }
}

このアプローチでは、各製品タイプに Product クラスのインスタンスがあり、注文を処理するために共通のロジックを共有できます。さらに、各製品タイプは、processSpecificOrder() などのメソッドを使用して、独自の特定のロジックを持つことができます。この設計はより柔軟であり、継承階層に影響を与えることなく、新しい製品タイプの導入やタイプ固有のロジックの変更が容易になります。

継承をいつ適用するか?

ソフトウェア設計における継承と合成のどちらを選択するかは、対処している問題のコンテキストと特定の要件によって異なります。以下に、合成よりも継承をより適切なオプションとして考慮できる状況をいくつか示します:

  • "is-a" 関係: クラス間に明確な "is-a" 関係がある場合、継承は特に適切です。クラス B がクラス A のより特殊なバージョンである場合、継承は理にかなっています。たとえば、Vehicle クラスと Car クラスがある場合、車は車両の一種であるため、「is-a」関係は明らかです。
class Vehiculo {
    // ...
}

class Automovil extends Vehiculo {
    // ...
}
  • コードの再利用: 派生クラスは基本クラスのメンバーとメソッドを継承するため、継承によりコードの再利用が可能になります。これは、関連するクラス間に大量の共通コードがある場合に有益です。
class Animal {
    void comer() {
        // Lógica común para comer
    }
}

class Perro extends Animal {
    void ladrar() {
        // Lógica específica para ladrar
    }
}
  • ポリモーフィズム: 継承はポリモーフィズムの実装の基礎であり、派生クラスが基本クラスから継承されたメソッドの特定の実装を提供できるようになります。これは、派生クラスのオブジェクトを均一に扱う必要があるシナリオで役立ちます。
class Figura {
    void dibujar() {
        // Lógica común para dibujar una figura
    }
}

class Circulo extends Figura {
    void dibujar() {
        // Lógica específica para dibujar un círculo
    }
}

class Cuadrado extends Figura {
    void dibujar() {
        // Lógica específica para dibujar un cuadrado
    }
}

  • 機能拡張: 既存の機能を拡張または特殊化する場合は、継承の方が自然な場合があります。たとえば、ライブラリを開発していて、基本機能を備えた基本クラスを提供する場合、ライブラリのユーザーはその基本クラスから派生してその機能を拡張できます。

不正な相続をするとどうなるでしょうか?

継承の長所と短所を評価し続けると、不適切な継承から発生する可能性のある問題の 1 つは、クライアントがインターフェイスに依存することを強制されるべきではないというインターフェイス分離原則に違反することになります。使用しないでください。すべての実装に関係のないメソッドを含む方法でインターフェイスが拡張された場合、そのインターフェイスを使用するクライアントは、必要のないメソッドを実装したり依存したりすることを余儀なくされる可能性があり、その結果、デザインがクリーンでなくなり、より困難になる可能性があります。維持する。

結論

要約すると、継承は「である」関係に焦点を当て、クラス階層をモデル化するために使用されますが、合成は「ある」関係に焦点を当て、他の単純なオブジェクトから複雑なオブジェクトを構築するために使用されます。どちらのアプローチにもそれぞれ固有の使用例があり、ソフトウェア設計における関係の構造と性質に基づいて選択されます。

リリースステートメント この記事は次の場所に転載されています: https://dev.to/rlgino/composicion-vs-herencia-4664?1 侵害がある場合は、[email protected] に連絡して削除してください。
最新のチュートリアル もっと>

免責事項: 提供されるすべてのリソースの一部はインターネットからのものです。お客様の著作権またはその他の権利および利益の侵害がある場合は、詳細な理由を説明し、著作権または権利および利益の証拠を提出して、電子メール [email protected] に送信してください。 できるだけ早く対応させていただきます。

Copyright© 2022 湘ICP备2022001581号-3