最近ちょうぜつソフトウェア設計入門――PHPで理解するオブジェクト指向の活用という本でデザインパターンの章があって、流石に最低限は覚えておかないと思ったのでメモ。
デザインパターンって何?
デザインパターンは名前だけ知ってる状態な人のために軽く説明。
ソフトウェア設計でよく起きる問題に対する典型的な解決方法のこと。以下の特徴があります。
- 実装方法が決まっているアルゴリズムと違い、パターンの指針に従い自分で実装する必要がある。
- 実証・テスト済み
- 〇〇パターン使っているよ!と他人に伝えるだけで意思疎通しやすくなる
今回紹介するデザインパターンについて
- refactoring.guruで上げられているパターンのうち、星が3かつ簡単なものを中心とした
- TypeScriptではあまり使われないもの/アンチパターンとされているものについては外している
- 10個も紹介したところで一気に覚えられないということで、5つだけに絞った
生成に関するパターン
Builderパターン
- 複雑なオブジェクトを段階的に構築するパターン
- -> プロパティの追加やリセットなど
コード例
今回は会社が保有している案件(プロジェクト)の設定を想定して書いている。
<クラス図- Builderパターン>
コード例- Builderパターン
interface Project {
name: string
skills: string[]
}
class ExampleBuilder {
private projects: Project[] = []
constructor() {}
public reset(): void {
this.projects = []
}
public projectFrontend(projectName: string): this {
this.projects.push({
name: projectName,
skills: ["typescript", "react", "scss"]
});
return this
}
public projectBackend(projectName: string): this {
this.projects.push({
name: projectName,
skills: ["php", "laravel", "mysql"]
});
return this
}
}
const builder = new ExampleBuilder()
builder.projectBackend("db migration project").projectFrontend("react project")
console.log(builder)
Factoryパターン
- 作成ロジックを外部に公開せず、内部でオブジェクトやクラスを返すパターン
- api環境の切り替え(本物のapiから取ってくるのか、モックから取ってくるのか..など)やmoduleの取得に使える
コード例
エンジニアが持っているモジュールを簡単に返却できるfactoryメソッドを作成した(クラスの中身を書いてないが、特別な理由がない限り、実際の業務では真似しないこと)。
<クラス図- Factoryパターン>
コード例- Factoryパターン
interface Module {}
class EngineerModule implements Module {}
class ProgramingModule implements Module {}
class ModuleFactory {
public engineer() {
return new EngineerModule()
}
public programing() {
return new ProgramingModule()
}
}
const moduleFactory = new ModuleFactory()
console.log(moduleFactory.engineer())
構造に関するパターン
Facadeパターン
- Facade = 「うわべ」「見せかけ」 という意味の英単語(英辞書)。
- 複数のサブシステムの処理をFacadeクラス内で行い、Facadeクラスは自身のメソッドでなにか行うことはなく、あくまで単純なメソッドで外部向けの「窓口」として振る舞う。
- Factoryパターンとは違い、クラス/オブジェクトそのものを返すのではなく、複数のサブクラスのメソッドを実行するのがポイント。
コード例
簡素なログイン・ログアウト処理を持ったSystemFacadeクラスを作成した。これでSystemFacadeクラスを窓口に、間接的にこれらの処理を呼び出せるようにしている。
<クラス図- Facadeパターン>
コード例- Facadeパターン
class User {
public setUser() {}
public resetUser() {}
}
class SystemId {
public setSystemId() {}
public resetSystemId() {}
}
class SystemFacade {
private user: User
private systemId: SystemId
constructor () {
this.user = new User()
this.systemId = new SystemId()
}
public login() {
this.user.setUser()
this.systemId.setSystemId()
}
public logout() {
this.user.resetUser()
this.systemId.resetSystemId()
}
}
const systemFacade = new SystemFacade()
systemFacade.login()
console.log(systemFacade)
systemFacade.logout()
console.log(systemFacade)
振る舞いに関するパターン
Stateパターン
- オブジェクトの状態を外部から変更・取得などを可能にします
- フロントエンドを触っている人なら、コンポーネントのstate管理、ReactでいうRedux/Vue.jsでいうVuexといったstore管理ライブラリと似たことをしていると思えばわかりやすいと思います。
コード例
仕事場をオフィスなのか、リモート(在宅)ワークなのを取得したり、変更できるコードを作成しました。
<クラス図- Stateパターン>
コード例- Stateパターン
interface State {
getState(): string
}
class OfficeState implements State {
getState() {
return 'work from office';
}
}
class FromHomeState implements State {
getState() {
return 'work from home';
}
}
class WorkLocation {
private state: State
constructor() {
this.state = new OfficeState()
}
changeLocation(state: State) {
this.state = state
}
getLocation() {
return this.state.getState()
}
}
const workLocation = new WorkLocation()
console.log(workLocation.getLocation())
Strategyパターン
- Strategy(戦略)を切り替えたり、実行できるパターンになります。
コード例
ここで使用するデザインパターンを設定するという想定で記載したコードとなります。
<クラス図- Strategyパターン>
コード例- Strategyパターン
interface Strategy {
doAction(): void
}
class FacadeStrategy implements Strategy {
doAction() {
console.log('do facade pattern');
}
}
class StateStrategy implements Strategy {
doAction() {
console.log('do state pattern');
}
}
class Programmer {
private strategy: Strategy
constructor() {
this.strategy = new FacadeStrategy()
}
changeStrategy(strategy: Strategy) {
this.strategy = strategy
}
request() {
return this.strategy.doAction()
}
}
const programmer = new Programmer()
console.log(programmer.request())
まとめ
デザインパターンに疎い筆者の観点で、5つ挙げてみました。バックエンド、フロントエンド…といった領域問わず参考にしていただけると幸いです。
参考サイト
-
refactoring.guru
- 最近日本語化されました。機械翻訳ではなく、しっかりとした日本語で説明されているためオススメです。
- Fireship - 10 Design Patterns in TypeScript