Java上級

上級 Javaで学ぶオブジェクト指向設計|アンチパターン編

導入

オブジェクト指向設計は、ソフトウェア開発において重要な役割を果たしますが、実際の業務では様々なアンチパターンに遭遇することが多いです。特に、設計時に不適切な選択をすることで、コードの可読性や保守性が低下し、後々の開発に悪影響を及ぼすことがあります。本記事では、Javaを用いた具体的なシチュエーションを通じて、よく見られるアンチパターンとその改善方法について考察します。

教科書レベルの解説(オブジェクト指向設計)

重要な概念の整理

オブジェクト指向設計の基本は、カプセル化、継承、ポリモーフィズムなどの概念にあります。これらを適切に利用することで、コードはより柔軟で再利用可能なものとなります。しかし、これらの概念を誤って適用すると、アンチパターンが発生します。特に、クラスの責任が不明確になることや、過度な継承構造が問題となります。

コード例(Java)


class Shape {
    public void draw() {
        System.out.println("Drawing a shape");
    }
}

class Circle extends Shape {
    public void draw() {
        System.out.println("Drawing a circle");
    }
}

class Square extends Shape {
    public void draw() {
        System.out.println("Drawing a square");
    }
}

class Drawing {
    public void renderShapes(List shapes) {
        for (Shape shape : shapes) {
            shape.draw();
        }
    }
}

コードの行ごとの解説

  1. Shapeクラスは基本的な形状を表現する親クラスです。
  2. CircleとSquareクラスはShapeを継承し、それぞれのdrawメソッドをオーバーライドしています。
  3. Drawingクラスは、Shapeのリストを受け取り、それぞれの形状を描画するrenderShapesメソッドを持っています。

アンチパターン編

このコード例では、継承を用いたシンプルな形状描画が実装されていますが、次のような問題が存在します。まず、Shapeクラスが持つdrawメソッドは、全ての形状に共通のインターフェースとして機能していますが、これが過度な拡張を招く可能性があります。たとえば、将来的に新しい形状を追加する際、Shapeクラスに新たなメソッドを追加する必要が生じ、継承関係が複雑化します。これにより、コードの可読性や保守性が低下します。

改善策としては、インターフェースを使用する方法があります。Shapeクラスをインターフェースに変更し、各形状がそのインターフェースを実装することで、柔軟性を持たせることができます。


interface Shape {
    void draw();
}

class Circle implements Shape {
    public void draw() {
        System.out.println("Drawing a circle");
    }
}

class Square implements Shape {
    public void draw() {
        System.out.println("Drawing a square");
    }
}

class Drawing {
    public void renderShapes(List shapes) {
        for (Shape shape : shapes) {
            shape.draw();
        }
    }
}

まとめ

  • オブジェクト指向設計におけるアンチパターンを理解することで、より良い設計が可能になります。
  • インターフェースを利用することで、コードの柔軟性や拡張性を高めることができます。