6️⃣
[読書メモ]オブジェクト設計スタイルガイド 7章1~2節 with TypeScript
オブジェクト設計スタイルガイドを読みながら、TypeScriptでやるならどうやるかを考えながら書きました。
要約的に読める内容になっていると思うので、サクッと3分ぐらいで読める記事となっています。
7 タスクの実行
7.1 コマンドメソッドには、命令形の名前を付ける
命令形で、短く、明確な名前を付けることで、コマンドメソッドを使う人が、そのメソッドを使いやすくなります。
良い名前の例: sendReminderEmail
7.2 コマンドメソッドでやることを限定し、イベントを使用して二次的なタスクを実行する
NG
function changeUserPassword(userID: string, newPassword: string) {
// ユーザーの取得
const user = userRepository.find(userID)
// パスワードの変更
user.password = newPassword
// パスワード変更後の処理
sendPasswordChangeEmail(user)
// パスワード変更後の処理
logPasswordChange(user)
}
OK:インベントを使用してタスクを複数に分ける
class UserPasswordChanged {
private UserID: string
constructor(userID: string) {
this.UserID = userID
}
get userID() {
return this.UserID
}
}
function changeUserPassword(userID: string, newPassword: string) {
// ユーザーの取得
const user = userRepository.find(userID)
// パスワードの変更
user.password = newPassword
// イベントの発行
eventDispatcher.dispatch(new UserPasswordChanged(userID))
}
class SendEmail {
whenUserPasswordChanged(event: UserPasswordChanged) {
this.mailer.sendPasswordChangeEmail(event.userID)
}
}
// EventDispatcherの実装
class EventDispatcher {
private listeners: any[] = []
constructor(listeners: any[]) {
this.listeners = listeners
}
dispatch(event: any) {
this.listeners.forEach(listener => {
if (listener.whenUserPasswordChanged) {
listener.whenUserPasswordChanged(event)
}
})
}
addListener(listener: any) {
this.listeners.push(listener)
}
}
const listener = new SendEmail()
const eventDispatcher = new EventDispatcher(
[
UserPasswordChanged => [listener, 'whenUserPasswordChanged']
]
)
eventDispatcher.dispatch(new UserPasswordChanged('user-id'))
メリットとして、コマンドメソッドがシンプルになり、コマンドメソッドの責務が明確になる。
また、コマンドメソッドが複数のリスナーに通知することができる。
デメリットとして、イベントの発行とイベントのリスナーの登録が分かれているため、コードが分散してしまう。
また、イベントの発行とリスナーの登録が分かれているため、リスナーの登録を忘れる可能性がある。
Discussion