1. ホーム
  2. oop

[解決済み] 抽象クラス vs. インターフェース vs. ミキシン

2023-06-14 21:29:45

質問

の違いについて、どなたか教えてください。 抽象クラス , インターフェース そして ミックスイン ? 私は自分のコードで前にそれぞれを使用したことがありますが、技術的な違いがわかりません。

どのように解決するのですか?

抽象クラス

抽象クラスは、インスタンス化されることを想定していないクラスです。抽象クラスは、実装を持たない、いくつかの実装を持つ、またはすべての実装を持つことができます。抽象クラスは、そのサブクラスが共通の(デフォルトの)実装を共有できるように設計されています。抽象クラスの(擬似的な)例としては、次のようなものがあります。

abstract class Shape {
    def abstract area();  // abstract (unimplemented method)
    def outline_width() = { return 1; }  // default implementation
}

サブクラスは次のようになります。

class Rectangle extends Shape {
    int height = width = 5;
    def override area() = { return height * width; }  // implements abstract method
    // no need to override outline_width(), but may do so if needed
}

可能な使用法

def main() = {
    Shape[] shapes = { new Rectangle(), new Oval() };
    foreach (s in shapes) {
        print("area: " + s.area() + ", outline width: " + s.outline_width());
    }
}

サブクラスが未実装のメソッドをオーバーライドしない場合、それはまた抽象クラスです。

インターフェース

一般的なコンピュータサイエンスの用語では、インターフェイスとはクライアントに対して公開されるプログラムの部分のことを指します。パブリッククラスやメンバはインターフェイスの例です。

JavaとC#では、特別な interface キーワードがあります。これらは多かれ少なかれ、実装を持たない抽象的なクラスです。(定数、ネストされたクラス、明示的な実装、アクセス修飾子については、ここでは触れませんが、トリックがあります)。Javaでは、この「実装を持たない」という部分はもう通用しませんが、デフォルトのメソッドが追加されました。その interface キーワードはインターフェースの概念を再定義したものと見ることができます。

シェイプの例に戻ると

interface Shape {
    def area();  // implicitly abstract so no need for abstract keyword
    def outline_width();  // cannot implement any methods
}

class Rectangle implements Shape {
    int height = width = 5;
    def override area() = { return height * width; }
    def override outline_width() = { return 1; }  // every method in interface must be implemented
}

def main() = {
    Shape[] shapes = { new Rectangle(), new Oval() };
    foreach (s in shapes) {
        print("area: " + s.area() + ", outline width: " + s.outline_width());
    }
}

JavaとC#は実装を伴うクラスの多重継承を認めていませんが、インターフェースの多重実装は認めています。JavaとC#では、インターフェイスを回避策として 死のダイヤモンド問題 に対する回避策としてインターフェイスを使用しています(適切に対処すればそれほど致命的ではありません)。

ミキシン

mixin (traitと呼ばれることもあります) は抽象クラスを多重継承させることができます。ミキシンは多重継承のような恐ろしい関連性を持たないので(C++の狂気のせい)、人々はより快適にそれらを使用することができます。しかし、それをサポートする言語は、C++よりもエレガントな方法でそれを軽減しているので、より良いものとして認識されています。

Mixin は、以下のようなインターフェイスとして歓迎されています。 動作の再利用 , より柔軟 インターフェース、そして より強力な インタフェースがあります。これらはすべて interface という用語があり、JavaとC#のキーワードを参照しています。 Mixinはインターフェースではありません。 多重継承です。もっときれいな名前です。

これはミキシンが悪いと言っているのではありません。多重継承が悪いわけではありません。C++が多重継承を解決する方法について、みんなが大騒ぎしているのです。

うんざりするほど古いシェイプの例について

mixin Shape {
    def abstract area();
    def outline_width() = { return 1; }
}

class Rectangle with Shape {
    int height = width = 5;
    def override area() = { return height * width; }
}

def main() = {
    Shape[] shapes = { new Rectangle(), new Oval() };
    foreach (s in shapes) {
        print("area: " + s.area() + ", outline width: " + s.outline_width());
    }
}

抽象クラスの例と違いがないことにお気づきでしょう。

もう一つおまけの豆知識として、C#はバージョン3.0からmixinをサポートしています。インターフェイスの拡張メソッドでミキシンを行うことができます。以下は、本物の(!)C#コードのmixinスタイルによるShapeの例です。

interface Shape
{
    int Area();
}

static class ShapeExtensions
{
    public static int OutlineWidth(this Shape s)
    {
        return 1;
    }
}

class Rectangle : Shape
{
    int height = 5;
    int width = 5;

    public int Area()
    {
        return height * width;
    }
}

class Program
{
    static void Main()
    {
        Shape[] shapes = new Shape[]{ new Rectangle(), new Oval() };
        foreach (var s in shapes)
        {
            Console.Write("area: " + s.Area() + ", outline width: " + s.OutlineWidth());
        }
    }
}