はじめに
この記事はGoodpatch Advent Calendar 2019 1日目の記事です。
今回は、GoFのデザインパターンを知らない・あるいは聞いたことはあるけど詳しくない人に向けて、2019年が終わる前に私自身の復習も兼ねて、分かりやすく紹介してみようという試みです。
ソフトウェア業界にいると「GoFのデザインパターン」という言葉を聞く機会もあるかなと思いますが、実際のところ、書籍「Java言語で学ぶデザインパターン入門」が発売されたのも随分前ですし、昨今のプログラミングにおいては使わないものもあると思います。もはやクラス継承、特に多段継承はアンチパターンという話もありますし...。
しかし、この書籍に書かれているデザインパターンは実務では使わずとも、背後にある考え方はプログラミングの基礎知識として一通り学んでおくのは有用なのではないかと思いました。パターンに名前をつけて、コミュニケーションを取りやすくしている点も良いと思います。
実際にとあるエンジニアリングマネージャーの方は、デザインパターンを学んでいたことが、今の組織設計にも活きているとおっしゃっていました。
GoFのデザインパターンとは
GoFのデザインパターンについて、Wikipediaでは以下のように説明されています。
ソフトウェア開発におけるデザインパターン(型紙(かたがみ)または設計パターン、英: design pattern)とは、過去のソフトウェア設計者が発見し編み出した設計ノウハウを蓄積し、名前をつけ、再利用しやすいように特定の規約に従ってカタログ化したものである。
書籍『オブジェクト指向における再利用のためのデザインパターン』において、GoF (Gang of Four; 四人組) と呼ばれる4人の共著者は、デザインパターンという用語を初めてソフトウェア開発に導入した。GoFは、エーリヒ・ガンマ、リチャード・ヘルム、ラルフ・ジョンソン、ジョン・ブリシディースの4人である。彼らは、その書籍の中で23種類のパターンを取り上げた。
デザインパターン
ここでは、私の独断と偏見で23種類のデザインパターンの中から5つのパターンを取り上げます。ちなみにこの記事ではUMLや具体的なコードは割愛し、現実世界で例えた場合の説明に重きを置いています。具体的に知りたい方はデザインパターン | TECHSCORE(テックスコア)をご参考ください。また、稚拙ではありますが、私が学習時に作ったTypeScriptのコードもこちらのリポジトリに上げてあります。
Template Methodパターン
Template Methodパターンは、なにかを作る際にベースとなる形を提供するパターンです。
たとえば、「あ」という形がくり抜かれたテンプレートを使えば、簡単にさまざまな「あ」を作ることができます。共通のテンプレートを利用することで、類似パターンの生成を楽にすることができます。
実際のプログラムでは、共通テンプレートをスーパークラスとして実装し、類似パターンをサブクラスとして実装します。共通テンプレートの処理が多ければ多いほど、類似パターンを作るのが楽になりますが、類似パターン側での自由度は減ってしまいますので、「何をどこまで共通するか」を考えるのが非常に重要なポイントになります。
Singletonパターン
Singletonパターンは、「絶対に1つしか作ってはいけない」という性質を持つものを作るときに使うパターンです。
たとえば、作業計画が書かれたホワイトボードがあり、作業計画を見ながら作業者が仕事をする場合、作業計画が書かれたホワイトボードは必ず1つにしておいた方が安全です。もし、ホワイトボードが2つや3つあると作業者はどれが正しいのか混乱してしまうでしょう。
実際のプログラムでは、クラスからインスタンスを生成する際に1度だけ生成できる仕組みを入れることで必ず1つであることを保証します。
インスタンスを**「1つしか生成できない」という制約は、逆に言えば「必ず1つである」という前提条件を増やす**ことができます。
Facadeパターン
Facadeパターンは、複雑な処理にシンプルな窓口を用意するパターンです。
たとえば、お客さんが何か困っているときにはサポート窓口とコミュニケーションを行い、サポート窓口の人が実際に困りごとを解決する人たちとコミュニケーションを取ります。お客さんは、裏で行われていることをいちいち把握せずとも問題を解決することができます。
実際のプログラムでは、既存のクラスやメソッドが複雑でごちゃごちゃしている場合にそれらをまとめる新しいインターフェースを用意します。
このパターンを使って、窓口となるインターフェースを作る場合には、それを利用する側が出来るだけシンプルに使えるように設計することが重要なポイントになります。シンプルにするというのはオプションを減らすなどして、余計な情報を見えなくするということです。
Strategyパターン
Strategyパターンは、その名の通り「戦略」を簡単に変更できるようにするパターンです。
たとえば、戦略案をいくつか持っている場合、必要なタイミングで戦略を選べるようにしておけば、後で戦略を変更することが楽になります。ユーザーの選択によって、アルゴリズムを切り替えたい場合などに利用することができます。
実際のプログラムでは、各戦略に共通のインターフェースを定義し、別のクラスに移譲して戦略となる処理を実行します。
Chain of Responsibilityパターン
Chain of Responsibilityパターンは、「要求する人」と「要求を処理する人」がいるとして、「何を要求してくるか分からないときに要求者をたらい回しにする」パターンです。
「要求する人」は「要求を処理する人」を順番に渡り歩き、自分の要求を満たすよう求めますが、「要求を処理する人」は自分が処理すべきかどうか判断し、処理すべきでない場合は何もしません。ここでは「要求を処理する人」が他の「要求を処理する人」のことを知らないことによって独立性が高まり、「要求する人」をたらい回しにすることで、「要求を処理する人」たちの負担を下げているということがポイントです。「要求を処理する人」が独立していることによって、新しく要求を処理する人を増やしたり、減らしたりすることが簡単になります。
もし、たらい回しにしない場合には誰かが「この要求に対してはこの係が処理する」という知識を持つ必要がありますが、これはスピードとメンテナンス性のトレードオフの問題です。
おわりに
いかがでしたでしょうか。説明文だけだと分かりにくいかもしれませんが、なんとなくデザインパターンの雰囲気について知れたり、デザインパターンに興味を持つきっかけになりましたら幸いです。
この記事は以下の書籍をベースとして書いたものですので、さらに詳しく知りたいという方は一度読んでみると良いかもしれません。