Abstract Factory

概要

一連のセットになるオブジェクトをその中身を具体的に知らなくても生成することができるようになるためのクラスを用意するパターン。

生成されるオブジェクトの整合性などが担保されやすくなる。

使い方

bad

interface Connection {};
class MySqlConnection implements Connection {}
class PostgresqlConnection implements Connection {}
class SqliteConnection implements Connection {}

interface QueryBuilder {};
class MySqlQueryBuilder implements QueryBuilder {}
class PostgresqlQueryBuilder implements QueryBuilder {}
class SqliteQueryBuilder implements QueryBuilder {}

const execOnMySql = (queryString: string) => {
  const queryBuilder = new MySqlQueryBuilder();
  const connection = new MySqlConnection();

  const query = queryBuilder.build(queryString)
  connection.execute(query);
}

execOnMySqlの中で生成されるインスタンスが全部MySqlのものかどうかの保証がない。 実行時のコードでちゃんと揃える必要がある。

また、RDBMSごとに実行メソッドや条件分岐を作る必要ができてしまう

good

interface Connection {};
class MySqlConnection implements Connection {}
class PostgresqlConnection implements Connection {}
class SqliteConnection implements Connection {}

interface QueryBuilder {};
class MySqlQueryBuilder implements QueryBuilder {}
class PostgresqlQueryBuilder implements QueryBuilder {}
class SqliteQueryBuilder implements QueryBuilder {}

interface SqlFactory {
  createConnection: () => Connection;
  createQueryBuilder: () => QueryBuilder:
}

class MySqlFactory {
  createConnection() {
    return new MySqlConnection();
  }
  createQueryBuilder() {
    return new MySqlQueryBuilder();
  }
}

class PostgresqlFactory {
}

class SqliteFactory {
}

const exec = (queryString: string, sqlFactory: SqlFactory) => {
  const queryBuilder = sqlFactory.createQueryBuilder();
  const connection = sqlFactory.createConnection();

  const query = queryBuilder.build(queryString)
  connection.execute(query);
}

QueryBuilderConnectionをセットで生成するようなFactoryクラスを用意することで、実行時の組み合わせなどを意識する必要がなくなった。

また、factoryを注入するようにしたことで、柔軟にRDBMSの組み合わせを変えられるようになった

使い所

  • セットでオブジェクトを生成したい時
    • そのセットに複数のバリエーションがある
  • 利用側から具体クラスを隠したい

参考