【PHP デザインパターン】Abstract Factory パターンと抽象クラスのabstract修飾子は別物です。


代表的なデザインパターンの一つである「Abstract Factory」を理解する上でこちらの「Abstract」という単語をPHPやその他開発言語で抽象クラスを作成する際に用いられる abstract 修飾子 の存在と混同しかけていましたので、この記事では2つの概念の違いを整理し、正しく理解していきます。

Abstract Factory パターンについての詳細は理解したい方は以下のZennの記事を参照してください。

PHP デザインパターン学習:Abstract Factory パターン – 関連するオブジェクト群をファミリーとして生成する

「abstract」キーワード – 言語の構文要素

PHPにおける「abstract」キーワードは、クラスやメソッドを抽象化するための言語構文です。

PHP マニュアル: クラスの抽象化

抽象クラス(abstract class)

抽象クラスは、それ自体ではインスタンス化できないクラスです。サブクラスによって継承され、具体的な実装を提供するためのテンプレートとして機能します。

abstract class Vehicle {
    abstract public function start();
    
    public function stop() {
        echo "車両が停止しました";
    }
}

class Car extends Vehicle {
    public function start() {
        echo "車のエンジンを始動します";
    }
}

// 使用例
$car = new Car();
$car->start(); // "車のエンジンを始動します"

上記の例では、Vehicleは抽象クラスで、start()メソッドは抽象メソッドです。具体的な車のクラスであるCarがこれを継承し、抽象メソッドを実装しています。

「Abstract Factory」パターン – 設計概念

一方、「Abstract Factory」パターンは、GoFによって定義された23のデザインパターンの一つであり、関連するオブジェクト群をファミリーとして生成するための設計概念です。

このパターン名の「Abstract」は、「抽象的な」という意味であり、具体的な実装の詳細から切り離された抽象的なインターフェースを通じてオブジェクト生成を行うという概念を表しています。

Abstract Factoryパターンの例

// Abstract Factoryパターンの例
interface UIFactory {
    public function createButton();
    public function createTextField();
}

class WindowsUIFactory implements UIFactory {
    public function createButton() {
        return new WindowsButton();
    }
    
    public function createTextField() {
        return new WindowsTextField();
    }
}

class MacUIFactory implements UIFactory {
    public function createButton() {
        return new MacButton();
    }
    
    public function createTextField() {
        return new MacTextField();
    }
}

ここでのUIFactoryはインターフェースであり、言語のabstractキーワードは使用していませんが、「Abstract Factory」パターンを実装しています。

Abstract Factoryパターンと抽象クラスの関係

Abstract Factoryパターンを実装する際、インターフェースの代わりに抽象クラスを使うこともできます:

// 抽象クラスを使ったAbstract Factoryパターンの実装
abstract class DatabaseFactory {
    abstract public function createConnection();
    abstract public function createQueryBuilder();
    
    // 共通機能を提供することも可能
    public function getFactoryInfo() {
        return "データベースファクトリ";
    }
}

class MySqlFactory extends DatabaseFactory {
    public function createConnection() {
        return new MySqlConnection();
    }
    
    public function createQueryBuilder() {
        return new MySqlQueryBuilder();
    }
}

この例では、言語のabstractキーワードを使って抽象クラスを定義し、それを使ってAbstract Factoryパターンを実装しています。しかし、この実装方法は必須ではなく、前者のinterfaceを使った実装も広く行われています。

理解するためのポイントを整理

  • Abstract Factoryパターンはもちろん抽象クラスを使って実装することもあるが、インターフェースを使うことも多い
  • Factoryを抽象クラスで定義することがAbstract Factoryパターンではない
  • abstractキーワードは言語の構文要素であり、Abstract Factoryはより高レベルの設計概念

まとめ

「Abstract Factory」パターンと「abstract」キーワードは、同じabstractという単語を用いますが、異なる概念です:

  • abstractキーワードは、PHPなどのプログラミング言語の構文要素であり、抽象クラスや抽象メソッドを定義するために使用します。
  • 「Abstract Factory」パターンは、関連するオブジェクト群をファミリーとして生成するための設計概念であり、インターフェースや抽象クラスはそれを実現するための手段です。

参考

Refactoring.Guru: Abstract Factory

Follow me!