5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ClassiAdvent Calendar 2016

Day 16

Swift で Rails の decorator みたいなのを作ってみる

Posted at

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 と同じようなことができるようになりました :tada:

感想

Model は綺麗になり、 View で使うやつだけ Decorator に定義すれば良くなりました :relaxed:
実際に使うかは検討中で、fullName くらいだったら Model が持っててもいいかなと思うけど、大きくデコる必要が出てきた時に使おうかなと思います。

また、Ruby は動的言語なのでコントローラ側で decorate しても、 View 側が decorate されてるかそうでないかを意識する必要があります。
Swift は静的言語なので明示的に UserDecorator 型で受ける必要があり、 fullName でアクセスできる型なのかが明示的で良いと思いました。

と言っても Rails の場合は動的型付けで同じ User と認識すれば良いのですが、Swift の場合全くの別クラスとなってしまうので Swift 的な流儀としてどうなのでしょうか。
それをするくらいなら extension 生やせば?とも思うので、状況によって使い分けしていきたいです。

おまけ: Decorator パターン

draper は Decorator パターン だという意見を見ましたが、新しいメソッドを生やすというのは Decorator パターンではないのでは?
Decorator パターンは継承をせずに再帰的に実行できるのが良いところで、新しいメソッドを生やすのは違うと思いました。

最後に

Classi 株式会社ではエンジニアを募集しています。
教育に興味ある人、ともに成長したい人来てくれ!!!頼む!!!

日本の教育を変える!先生・生徒向けアプリを作るiOSエンジニア募集! - Wantedly

5
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?