Classi Advent Calendar 2016 16 日目です!
iOS のアーキテクチャを悩んでいる時に、 Rails の decorator について教えてもらったので、それを Swift で実践してみます。
Rails の decorator って?
有名どころはここら辺。
View で表示するために Model のデータを加工したいとき、 Model にメソッドを生やす手段が一番早い。
でも、 View で使うだけのメソッドを Model に記述するのは責務的にどうなの?
という時に使うやつで、使い方は以下のように書きます。
# decorate してない場合は full_name にアクセスできない
@user = User.first
p @user.full_name
# => method_missing
# decorate したあとは full_name にアクセスできる
@user = User.first.decorate
p @user.full_name
# => "宮本 フレデリカ"
Model に extension 生やす (今までのやり方)
class User {
let lastName: String
let firstName: String
init(firstName: String, lastName: String) {
self.firstName = firstName
self.lastName = lastName
}
}
extension User {
var fullName: String {
return lastName + " " + firstName
}
}
let user = User(firstName: "卯月", lastName: "島村")
print(user.fullName)
// => 島村 卯月
Model に fullName のプロパティを生やした。
fullName は画面に表示するためだけに使うので、 Model にあるのおかしいのでは?
Decoration してみる
// 普通に User クラスを作る
class User {
let lastName: String
let firstName: String
init(firstName: String, lastName: String) {
self.firstName = firstName
self.lastName = lastName
}
}
// draper の User.first.decorate のようにアクセス出来るようにする
extension User {
var decorate: UserDecorator {
return UserDecorator(user: self)
}
}
// Decoration クラスを作成し、 fullName プロパティを生やす
class UserDecorator {
private let user: User
init(user: User) {
self.user = user
}
var fullName: String {
return user.lastName + " " + user.firstName
}
}
使い方:
let user = User(firstName: "凛", lastName: "渋谷")
let decoratedUser = UserDecorator(user: user)
print(decoratedUser.fullName)
// => 渋谷 凛
let decoratedUser2 = User(firstName: "未央", lastName: "本田").decorate
print(decoratedUser2.fullName)
// => 本田 未央
これで ruby と同じようなことができるようになりました ![]()
感想
Model は綺麗になり、 View で使うやつだけ Decorator に定義すれば良くなりました ![]()
実際に使うかは検討中で、fullName くらいだったら Model が持っててもいいかなと思うけど、大きくデコる必要が出てきた時に使おうかなと思います。
また、Ruby は動的言語なのでコントローラ側で decorate しても、 View 側が decorate されてるかそうでないかを意識する必要があります。
Swift は静的言語なので明示的に UserDecorator 型で受ける必要があり、 fullName でアクセスできる型なのかが明示的で良いと思いました。
と言っても Rails の場合は動的型付けで同じ User と認識すれば良いのですが、Swift の場合全くの別クラスとなってしまうので Swift 的な流儀としてどうなのでしょうか。
それをするくらいなら extension 生やせば?とも思うので、状況によって使い分けしていきたいです。
おまけ: Decorator パターン
draper は Decorator パターン だという意見を見ましたが、新しいメソッドを生やすというのは Decorator パターンではないのでは?
Decorator パターンは継承をせずに再帰的に実行できるのが良いところで、新しいメソッドを生やすのは違うと思いました。
最後に
Classi 株式会社ではエンジニアを募集しています。
教育に興味ある人、ともに成長したい人来てくれ!!!頼む!!!