概要
原著者の許諾を得て翻訳・公開いたします。
- 英語記事: Delegate to simplify your code - Andy Croll
- 原文公開日: 2018/08/05
- 著者: Andy Croll
日本語タイトルは内容に即したものにしました。
Rails: コードをシンプルにする2種類の委譲(翻訳)
オブジェクト指向プログラミングは、オブジェクト間のメッセージ受け渡しと考えることができます。
関連オブジェクトでは多くの場合、元のオブジェクトのメソッドであるかのように関連オブジェクトのpublicメソッドとしてアクセスできます。
これを実現する主な方法は次の2つです。
変更前
関連オブジェクトを直接呼び出す新しいメソッドを書く。
# 素のRuby
class Workspace
attr_reader :user
def initialize(user)
@user = user
end
def user_email
@user.email
end
end
# Railsの場合
class Workspace < ApplicationRecord
belongs_to :user
def user_email
user.email
end
end
変更後
Forwardable
の機能かdelegate
メソッドを用いる。
# 素のRuby
class Workspace
extend Forwardable
attr_reader :user
def initialize(user)
@user = user
end
def_delegator :@user, :email, :user_email
end
# Railsの場合
class Workspace < ApplicationRecord
belongs_to :user
delegate :email, to: :user, allow_nil: true, prefix: true
# allow_nil: trueにするとuserがnilの場合にエラーにならない
# prefix: trueにするとメソッド名がuser_emailになる
end
そうすべき理由
RubyやRailsでメッセージを「パススルー」する場合、いずれかのスタイルで新しいメソッドを作成するのが望ましい方法です。これによりコードで達成しようとしていることが明確に表現できます。「単に関連オブジェクトのメソッドを呼び出す」ことと「新しい機能を実際に実装する」ことの違いを見た目ではっきりと区別できるようになり、便利です。
Railsの場合のコードでは、構文が洗練され、柔軟性も機能も向上するのが普通です。私が特に気に入っているのは、prefix
オプションとallow_nil
オプションです。Railsをお使いの方は、Railsがdelegation向けに提供している拡張機能をこの方法で利用できます。
そうしない理由があるとすれば
これらの機能を使ってworkspace.user.email
がworkspace.user_email
に改善されるぐらいでは大したメリットは感じられません。しかしメソッド名をworkspace.owner_email
などに変更する場合は、意図が明確になるというメリットもあるでしょう。
RubyのDelegator
ライブラリ(ドキュメント)など、委譲の手法は他にもありますが、しかしこれらはいくつかのメソッドを渡すよりも、機能ごとクラス全体をラップする場合に使う方が便利です。