はじめに
その1の続き。今回はオブジェクトの構造に関するパターンについてです。
- オブジェクトの構造に関するパターン
- Adapter パターン
- Bridge パターン
- Composite パターン
- Decorator パターン
- Facade パターン
- Flyweight パターン
- Proxy パターン
その1同様、基本的には下記2つを参考に書いてます。
github でこんなんみつけたのでこれ見ればいいと思うよ!(私まだ理解してないので。。。)
ochococo/Design-Patterns-In-Swift
Adapter パターン
異なる2つのインターフェースを変換してつなげる仕組み。ラッパー??みたいなやつだと思う。
Target と Adaptee を Adapter を介してつなげるらしい。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
struct Adaptee { let value: Float func printValue() { print("value: \(value)") } } protocol Target { var value: Double { get } func printValue() } struct Adapter: Target { var value: Double { return Double(adaptee.value) } private let adaptee: Adaptee func printValue() { adaptee.printValue() } init(adaptee: Adaptee) { self.adaptee = adaptee } } class Hoge { func hogehoge() { let target = Adaptee(value: 10.5) let adapter = Adapter(adaptee: target) adapter.printValue() } } |
Android の ListView とかの Adapter はこれなのか??
Bridge パターン
クラスなどの実装と、呼出し側の間の橋渡しをするクラスを用意し、実装を隠蔽する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
protocol Animal { var impl: MoveImpl? { get } func move() } extension Animal { func move() { impl?.move() } } protocol MoveImpl { func move() } struct RunMoveImpl: MoveImpl { func move() { print("Run!") } } struct SwimMoveImpl: MoveImpl { func move() { print("Swim!") } } struct JumpMoveImpl: MoveImpl { func move() { print("Jump!") } } struct Cat: Animal { var impl: MoveImpl? } struct Fish: Animal { var impl: MoveImpl? } class Hoge { func hogehoge() { var cat = Cat() cat.impl = RunMoveImpl() cat.move() // Run! cat.impl = JumpMoveImpl() cat.move() // Jump! var fish = Fish() fish.impl = SwimMoveImpl() fish.move() // Swim! } } |
使い方はこれであってんのかな??
Composite パターン
木構造モデルを一つのオブジェクトとして操作する仕組み。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
protocol Component { var name: String { get } var isReadable: Bool { get set } func setUnreadable() } class Directory: Component, CustomStringConvertible { var description: String { return "name: \(name), isReadable: \(isReadable), subs: \(subs)" } let name: String var isReadable = true var subs: [Component] func setUnreadable() { isReadable = false for sub in subs { sub.setUnreadable() } } init(name: String, subs: [Component]) { self.name = name self.subs = subs } } class File: Component, CustomStringConvertible { var description: String { return "name: \(name), isReadable: \(isReadable)" } let name: String var isReadable = true func setUnreadable() { isReadable = false } init(name: String) { self.name = name } } class Hoge { func hogehoge() { let subFiles: [File] = [.init(name: "SubFile1"), .init(name: "SubFile3"), .init(name: "SubFile2")] let subDirectory = Directory(name: "Subs", subs: subFiles) let rootDirectory = Directory(name: "Root", subs: [subDirectory, File(name: "File1")]) print(rootDirectory) rootDirectory.setUnreadable() print(rootDirectory) } } // 一個目のプリント(isReadableはtrue) // name: Root, isReadable: true, subs: [name: Subs, isReadable: true, subs: [name: SubFile1, isReadable: true, name: SubFile3, isReadable: true, name: SubFile2, isReadable: true], name: File1, isReadable: true] // 二個目のプリント(isReadableがfalseになる) // name: Root, isReadable: false, subs: [name: Subs, isReadable: false, subs: [name: SubFile1, isReadable: false, name: SubFile3, isReadable: false, name: SubFile2, isReadable: false], name: File1, isReadable: false] |
View
も Composite パターンになるのかな??
Decorator パターン
既存のクラスを修正することなく機能を追加する仕組み。(きっとデコレーションするって意味だと思う)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
protocol Item { var price: Double { get } } protocol Topping: Item { var item: Item { get } } struct Pancake: Item { var price: Double { return 300 } } struct Chocolate: Topping { var item: Item var price: Double { return item.price + 100 } } struct WhippedCream: Topping { var item: Item var price: Double { return item.price + 120 } } class Hoge { func hogehoge() { let order = WhippedCream(item: Pancake()) print(order.price) let order2 = WhippedCream(item: Chocolate(item: Pancake())) print(order2.price) } } |
これでパンケーキクラス(構造体だけど)をいじらずにチョコレートやホイップクリームをトッピングできるようになった!
Facade パターン
複数のオブジェクトの連携でひとつの処理をするときに窓口を使って操作する仕組み。(ファサードは外観とかそういう意味っぽい)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
class Facade { private let objectA = ObjectA() private let objectB = ObjectB() func operation() { objectA.methodA() objectB.methodB() } } class ObjectA { func methodA() { } } class ObjectB { func methodB() { } } |
ちょっと具体的な処理については思いつかなかった。。。
参考サイトには下記のように書いてあった。。。1:1だと Adapterらしい。
Adapter や Decorator パターンなどの、単一のオブジェクト関係に着目したものと異なり、Facade は複数のオブジェクトを集約するラッパークラスです。
ラッパークラスのメソッドが、つねにひとつの内部オブジェクトに 1:1 でマップされる場合、それがいくら矢面に立つ受付であっても、それは Adapter です。
Flyweight パターン
既存のインスタンスがあればそれを共有して負荷を減らす仕組み。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
struct Book { let id: String let name: String } protocol BookSearching { func search(id: String, name: String) -> Book? } final class Library: BookSearching { private var books: [String: Book] = [:] func search(id: String, name: String) -> Book? { if books.index(forKey: id) == nil { books[id] = Book(id: id, name: name) } return books[id] } } class Hoge { func hogehoge() { let library = Library() let book = library.search(id: "12345", name: "ほげほげ本") } } |
Proxy パターン
ユーザと対象オブジェクトの間に入って対象オブジェクトの代理としてユーザとやり取りする仕組み。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
protocol HEVSuitMedicalAid { func administerMorphine() -> String } final class HEVSuit: HEVSuitMedicalAid { func administerMorphine() -> String { return "Morphine administered." } } final class HEVSuitHumanInterface: HEVSuitMedicalAid { lazy private var physicalSuit: HEVSuit = HEVSuit() func administerMorphine() -> String { return physicalSuit.administerMorphine() } } |
よくわかんなかったので ochococo/Design-Patterns-In-Swift の Virtual Proxy載せときます。
Decorator と似てるけど Decorator は機能拡張が目的で Proxy は効率的な運用が目的らしい。
さいごに
うーん。。。なんとなくわかった気になったけど実務で使えるレベルではない。。。
きっと数年後見返したときに何か気づきがあるだろう。たぶんなんで使うかっていう目的がよくわかってないからな気がするので目的については後日追記するかも。。。
参考
- オブジェクト指向言語を学ぶ人のための ザックリ理解するデザインパターン
- マンガでわかる Adapter
- マンガでわかる Bridge
- マンガでわかる Composite
- マンガでわかる Decorator
- マンガでわかる Facade
- マンガでわかる Flyweight
- マンガでわかる Proxy
コメント
[…] その2の続き。今回はオブジェクトの振る舞いに関するパターンについてです。 […]