Upgrade to Pro — share decks privately, control downloads, hide ads and more …

アプリケーションデザイン_5.pdf

k-kohey
July 19, 2019
110

 アプリケーションデザイン_5.pdf

k-kohey

July 19, 2019
Tweet

Transcript

  1. final class SingltonClass { private static var shared: SingltonClass? =

    nil static func instance() -> SingltonClass { if let shared = self.shared { return shared } return .init() } } 4JOHMFUPOύλʔϯ • 特徴 • PublicかつStaticなメソッドを通じてシステム上において唯⼀のインスタンスを取得する. • Publicなコンストラクタを持たない. 5
  2. 4JOHMFUPOύλʔϯΛ༻͍ΔϝϦοτٴͼσϝϦοτ • クロスプラットフォーム • RMIなどを⽤いて,他のJVMに共有できる. • あらゆるクラスに適応可能 • コントラスタをprivateにして共有インスタンスを返すメソッドを⽣ やせば良い

    • 派⽣を使って⽣成することも可能 • ⾃分を返すのではなくて,⼦クラスを返せる. • 評価が簡単 • Singletonが使わなければインスタンスは決して⽣成されない. • オブジェクトの破壊が定義されていない • シングルトンへの参照を持ったあるクラスがそのシングルトンを破 壊すると,別のクラスがそのシングルトンに参照しようとすると別 のシングルトンインスタンスが⽣成されてしまう. • シングルトンを破壊するいい⽅法がない. • 継承できない • 単純に継承しただけでは派⽣クラスはシングルトンになってくれな い. • 効率性 • インスタンスを⽣成するたび(以降,これをinstance()と呼ぶ)にIf ⽂が実⾏されるが,それが役⽴つのは最初の⼀回だけ. • 分かりづらい • Instance()を介することを知っていなければならない. 6 メリット デメリット
  3. .POPTUBUFύλʔϯΛ༻͍ΔϝϦοτٴͼσϝϦοτ • わかりやすさ • クライアントはMonostateを普通のオブジェクトと同じようなイン タフェースから扱える. • 派⽣可能 • MonostateのサブクラスはMonostateである

    • ポリモーフィズム • Monostateのメソッドはstaticではないので,派⽣クラスの中でオー バーライド出来る • ⽣成と破壊の定義が明確 • Monostateの変数はstaticであるから • 変換不可能 • あるMonosteateではないクラスを継承してMonosteateにすると いったことが出来ない. • 効率性 • Monostateは本物のオブジェクトを⽣成する • 存在 • Monostateの変数は全く使われなくともメモリスペースを消費する. • プラットフォームに依存 • JVMのインスタンスあるいは複数のプラットフォームから Monostateを共有することが出来ない. 8 メリット デメリット
  4. .POPTUBUFύλʔϯΛ༻͍ͨྫ • 特徴 • 異なる2つ以上のインスタンスに対してそれらが同⼀であるように振る舞わせることによって,共有するインスタンスの唯⼀性を 保証する⽅法. • Singletonが唯⼀性を保証する構造に着⽬している⼀⽅で,Monostateパターンは振る舞いを保証している. • Monostateパターンは振る舞いを担保しているので,Singletonのテストケースもパス出来る.

    10 class Turnstile { static var isLocked = true static var isAlarming = false static var coins = 0 static var refunds = 0 static let locked = Locked() static let unlocked = Unlocked() static var state: Turnstile = locked func reset() { Turnstile.isLocked = true Turnstile.isAlarming = false Turnstile.coins = 0 Turnstile.refunds = 0 Turnstile.state = Turnstile.locked } func deposit() { Turnstile.coins += 1 } func refund() { Turnstile.refunds += 1 } func pass() { Turnstile.state.pass() } func coin() { Turnstile.state.coin() } } final class Locked: Turnstile { override func coin() { Locked.state = Locked.unlocked Locked.isLocked = false Locked.isAlarming = false deposit() } override func pass() { Locked.isAlarming = true } } final class Unlocked: Turnstile { override func coin() { refund() } override func pass() { Unlocked.isLocked = true Unlocked.state = Unlocked.unlocked } }
  5. .POPTUBUFύλʔϯΛ༻͍ͨྫ • 特徴 • 異なる2つ以上のインスタンスに対してそれらが同⼀であるように振る舞わせることによって,共有するインスタンスの唯⼀性を 保証する⽅法. • Singletonが唯⼀性を保証する構造に着⽬している⼀⽅で,Monostateパターンは振る舞いを保証している. • Monostateパターンは振る舞いを担保しているので,Singletonのテストケースもパス出来る.

    11 class Turnstile { static var isLocked = true static var isAlarming = false static var coins = 0 static var refunds = 0 static let locked = Locked() static let unlocked = Unlocked() static var state: Turnstile = locked func reset() { Turnstile.isLocked = true Turnstile.isAlarming = false Turnstile.coins = 0 Turnstile.refunds = 0 Turnstile.state = Turnstile.locked } func deposit() { Turnstile.coins += 1 } func refund() { Turnstile.refunds += 1 } func pass() { Turnstile.state.pass() } func coin() { Turnstile.state.coin() } } final class Locked: Turnstile { override func coin() { Locked.state = Locked.unlocked Locked.isLocked = false Locked.isAlarming = false deposit() } override func pass() { Locked.isAlarming = true } } final class Unlocked: Turnstile { override func coin() { refund() } override func pass() { Unlocked.isLocked = true Unlocked.state = Unlocked.unlocked } } 2つの状態を派⽣クラスに譲渡(ポリモーフィズム可能)
  6. .POPTUBUFύλʔϯΛ༻͍ͨྫ • 特徴 • 異なる2つ以上のインスタンスに対してそれらが同⼀であるように振る舞わせることによって,共有するインスタンスの唯⼀性を 保証する⽅法. • Singletonが唯⼀性を保証する構造に着⽬している⼀⽅で,Monostateパターンは振る舞いを保証している. • Monostateパターンは振る舞いを担保しているので,Singletonのテストケースもパス出来る.

    12 class Turnstile { static var isLocked = true static var isAlarming = false static var coins = 0 static var refunds = 0 static let locked = Locked() static let unlocked = Unlocked() static var state: Turnstile = locked func reset() { Turnstile.isLocked = true Turnstile.isAlarming = false Turnstile.coins = 0 Turnstile.refunds = 0 Turnstile.state = Turnstile.locked } func deposit() { Turnstile.coins += 1 } func refund() { Turnstile.refunds += 1 } func pass() { Turnstile.state.pass() } func coin() { Turnstile.state.coin() } } final class Locked: Turnstile { override func coin() { Locked.state = Locked.unlocked Locked.isLocked = false Locked.isAlarming = false deposit() } override func pass() { Locked.isAlarming = true } } final class Unlocked: Turnstile { override func coin() { refund() } override func pass() { Unlocked.isLocked = true Unlocked.state = Unlocked.unlocked } } 派⽣クラスもMonostate
  7. .POPTUBUFύλʔϯΛ༻͍ͨྫ 13 class Turnstile { static var isLocked = true

    static var isAlarming = false static var coins = 0 static var refunds = 0 static let locked = Locked() static let unlocked = Unlocked() static var state: Turnstile = locked func reset() { Turnstile.isLocked = true Turnstile.isAlarming = false Turnstile.coins = 0 Turnstile.refunds = 0 Turnstile.state = Turnstile.locked } func deposit() { Turnstile.coins += 1 } func refund() { Turnstile.refunds += 1 } func pass() { Turnstile.state.pass() } func coin() { Turnstile.state.coin() } } final class Locked: Turnstile { override func coin() { Locked.state = Locked.unlocked Locked.isLocked = false Locked.isAlarming = false deposit() } override func pass() { Locked.isAlarming = true } } final class Unlocked: Turnstile { override func coin() { refund() } override func pass() { Unlocked.isLocked = true Unlocked.state = Unlocked.unlocked } } Monostateを普通のクラスに戻すのは難しい !
  8. /VMM 0CKFDUύλʔϯΛ༻͍ͨྫ 18 protocol EmployeeType { func isTiemToPay(_ date: Date)

    -> Bool func pay() } final class Employee: EmployeeType { private final class NullEmployee: EmployeeType { func isTiemToPay(_ date: Date) -> Bool { return false } func pay() { //何もしない return } } static let Null: EmployeeType = NullEmployee() func isTiemToPay(_ date: Date) -> Bool { // 何かしらの制御 let shouldPay = true return shouldPay } func pay() { // 何かしらの制御 } } // 何かしらの制御 let employee = DB.get(named: "Bob") if employee.isTimeToPay(Date()) { faile() } let employee = DB.get(named: "Bob") if employee == Employee.Null { faile() }
  9. /VMM 0CKFDUύλʔϯΛ༻͍ͨྫ 19 protocol EmployeeType { func isTiemToPay(_ date: Date)

    -> Bool func pay() } final class Employee: EmployeeType { private final class NullEmployee: EmployeeType { func isTiemToPay(_ date: Date) -> Bool { return false } func pay() { //何もしない return } } static let Null: EmployeeType = NullEmployee() func isTiemToPay(_ date: Date) -> Bool { // 何かしらの制御 let shouldPay = true return shouldPay } func pay() { // 何かしらの制御 } } // 何かしらの制御 let employee = DB.get(named: "Bob") if employee.isTimeToPay(Date()) { faile() } let employee = DB.get(named: "Bob") if employee == Employee.Null { faile() } 何もしないNullEmployeeを作る
  10. /VMM 0CKFDUύλʔϯΛ༻͍ͨྫ 20 protocol EmployeeType { func isTiemToPay(_ date: Date)

    -> Bool func pay() } final class Employee: EmployeeType { private final class NullEmployee: EmployeeType { func isTiemToPay(_ date: Date) -> Bool { return false } func pay() { //何もしない return } } static let Null: EmployeeType = NullEmployee() func isTiemToPay(_ date: Date) -> Bool { // 何かしらの制御 let shouldPay = true return shouldPay } func pay() { // 何かしらの制御 } } // 何かしらの制御 let employee = DB.get(named: "Bob") if employee.isTimeToPay(Date()) { faile() } let employee = DB.get(named: "Bob") if employee == Employee.Null { faile() } NullEmployeeは必ずfalseを返すので, Nullチェックは不要
  11. /VMM 0CKFDUύλʔϯΛ༻͍ͨྫ 21 protocol EmployeeType { func isTiemToPay(_ date: Date)

    -> Bool func pay() } final class Employee: EmployeeType { private final class NullEmployee: EmployeeType { func isTiemToPay(_ date: Date) -> Bool { return false } func pay() { //何もしない return } } static let Null: EmployeeType = NullEmployee() func isTiemToPay(_ date: Date) -> Bool { // 何かしらの制御 let shouldPay = true return shouldPay } func pay() { // 何かしらの制御 } } // 何かしらの制御 let employee = DB.get(named: "Bob") if employee.isTimeToPay(Date()) { faile() } let employee = DB.get(named: "Bob") if employee == Employee.Null { faile() } NullEmployeeをシングルトンにすることで 従来のような⽐較も可能