Slide 1

Slide 1 text

Swiftでデザインパターン10個 HatoChan

Slide 2

Slide 2 text

GoFのデザインパターン ෼ྨ ύλʔϯ໊ ੜ੒ "CTUSBDU'BDUPSZ 'BDUPSZ.FUIPE 4JOHMFUPO #VJMEFS 1SPUPUZQF ߏ଄ "EBQUPS #SJEHF $PNQPTJUF %FDPSBUPS 'BDBEF 'MZXFJHIU 1SPYZ ৼΔ෣͍ $IBJOPG3FTQPOTJCJMJUZ $PNNBOE *OUFSQSFUFS *UFSBUPS .FEJBUPS .FNFOUP 0CTFSWFS 4UBUF 4USBUFHZ 5FNQMBUF.FUIPE 7JTJUPS

Slide 3

Slide 3 text

Singletonパターン class Singleton { class var shared : Singleton { struct Static { static let instance : Singleton = Singleton() } return Static.instance } } ! let instance = Singleton.shared TUSVDUͷTUBUJDఆ਺Ͱఆٛ class Singleton { class var sharedInstance : Singleton { struct Static { static var onceToken : dispatch_once_t = 0 static var instance : Singleton? = nil } dispatch_once(&Static.onceToken) { Static.instance = Singleton() } return Static.instance! } } class Singleton { class var sharedInstance : Singleton { return _SingletonSharedInstance } } let _SingletonSharedInstance = Singleton() άϩʔόϧม਺Ͱఆٛ EJTQBUDI@PODFͰ࣮૷ .FNP ! ΫϥεͷΠϯελϯε͕Ұ͔ͭ͠ͳ͍͜ͱΛ อূ͍ͨ͠৔߹ͷύλʔϯͩΑɻ ! 4JOHMFUPOύλʔϯ͸TUSVDUͷTUBUJDఆ਺Ͱఆٛ͢Δͷ͕Ұ൪ ͖ͬ͢Γɻ ! タイププロパティ UZQFQSPQFSUJFT ΠϯελϯεͰ͸ͳ͘ɺ Ϋϥε΍ߏ଄ମɺenumࣗମʹϓϩύςΟΛఆٛ͢Δ͜ͱɻ TUSVDU4BNQMF4USVDUVSF\ TUBUJDWBSUZQF1SPQFSUZ ^ FOVN4BNQMF&OVNFSBUJPO\ TUBUJDWBSUZQF1SPQFSUZ ^ DMBTT4BNQMF$MBTT\ DMBTTWBSUZQF1SPQFSUZ\ SFUVSO ^ ^ structͱenumɺ஋౉͠ͷ͜ΕΒͷλΠϓʹ͸staticΛ࢖͏ Αɻ ࢀর౉͠ͷclassʹ͸classΛ࢖͏Αɻ

Slide 4

Slide 4 text

Singletonパターン(つづき) class NabeApi { private class var shared : NabeApi { struct Static { static let instance : NabeApi = NabeApi() } return Static.instance } class func graphUser(string : String) { shared.graphMeLogic(string) } func graphMeLogic(string: String) { print("graphUserLogic: \(string)") } } ! NabeApi.graphUser("nabe") .FNP TIBSFEͱ͔TIBSFE*OTUBODF͸Ӆṭ ͯ͠λΠϓϝιουʹͨ͠ํ͕͔ͬ͜ ͍͍Α

Slide 5

Slide 5 text

Builderパターン class SampleBuilderClass { @IBOutlet var profileImageView: UIImageView? @IBOutlet var nameLabel: UILabel? ! typealias SampleBuilderClosure = (SampleBuilderClass) -> Void init(buildClosure: SampleBuilderClosure) { // 実際はInterface Builderで⽣生成 profileImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 320, height: 40)) nameLabel = UILabel(frame: CGRect(x: 0, y: 40, width: 320, height: 40)) buildClosure(self) } } ! let sampleBuilderClass = SampleBuilderClass(buildClosure: {(sampleBuilderInstance) -> Void in sampleBuilderInstance.nameLabel?.text = "hato" let url = NSURL.URLWithString("http://www.sekkisei.com/images/white_bb/img_main.png"); var err: NSError?; var imageData :NSData = NSData.dataWithContentsOfURL(url,options: NSDataReadingOptions.DataReadingMappedIfSafe, error: &err); sampleBuilderInstance.profileImageView?.image = UIImage(data:imageData) }) ! sampleBuilderClass.nameLabel?.text sampleBuilderClass.profileImageView?.image .FNP ΦϒδΣΫτͷੜ੒Λந৅Խͯ͠؆ܿʹ͢ΔύλʔϯͩΑɻෳࡶͳΫϥεɺ਺ଟ͘ͷΠ χγϟϥΠζύϥϝʔλʹ௚໘ͨ࣌͠ʹ͸ϏϧμʔΛݕ౼͢ΔΑɻΑ͘ϝιουνΣʔ ϯͷλΠϓΛݟΔ͚Ͳɺࠓճ͸DMPTVSFͰɻ DMPTVSFͷجຊܗ { (parameters) -> return type in statements } closureの書き⽅方は⾊色々あるよ closureの例 reversed = sorted(names, { (s1: String, s2: String) -> Bool in return s1 > s2 } ) 型推論 SFWFSTFETPSUFE OBNFT \T TJOSFUVSOTT^ SFUVSOলུ SFWFSTFETPSUFE OBNFT \T TJOTT^ γϣʔτϋϯυҾ਺໊ SFWFSTFETPSUFE OBNFT \^ 0QFSBUPSؔ਺ SFWFSTFETPSUFE OBNFT

Slide 6

Slide 6 text

Prototypeパターン class PrototypeTextClass { var text: String? let font: UIFont init(font: UIFont) { self.font = font } func clone() -> PrototypeTextClass { return PrototypeTextClass(font:self.font) } } ! let prototypeText = PrototypeTextClass(font:UIFont.systemFontOfSize(14.0)) ! let nabeText = prototypeText.clone() nabeText.text = "nabe" ! let horiminText = prototypeText.clone() horiminText.text = "horimin" .FNP ! ΋ͱͷΠϯελϯεΛݪܕͱͯ͠Π ϯελϯεΛੜ੒͢ΔΑ͏ʹ͢Δͨ ΊͷύλʔϯͩΑɻ ! KBWBͩͱݴޠ࢓༷ͱͯ͠DMPOFBCMFΠϯλ ϑΣʔε͕͋ΔΑɻ ! KBWBTDSJQU͸શͯͷؔ਺ΦϒδΣΫτʹ QSPUPUZQFϓϩύςΟ͕͋ΔΑɻΦϒδΣ Ϋτ͸ผͳΦϒδΣΫτΛϓϩτλΠϓʹ ͯ͠ಠࣗͷಛ௃Λ෇Ճ͍ͯ͘͠ͱ͍͏ߟ͑ ํͷϓϩτλΠϓϕʔεΦϒδΣΫτࢦ޲ ݴޠͩΑɻ

Slide 7

Slide 7 text

Compositeパターン protocol FileProtocol { func remove() -> Void } ! class File : FileProtocol { var name : String? init(name: String) { self.name = name } func remove() -> Void{ print("Remove \(self.name)") } } ! class Directory : FileProtocol { var name : String? lazy var files : Array = [] init(name: String) { self.name = name } ! func add(file : FileProtocol) -> Void { self.files.append(file) } func remove() -> Void { for f in self.files { f.remove() } print("Remove \(self.name)") } } ! ! let d1 : Directory = Directory(name:"maruko") let f1 : File = File(name:"tasaka") let f2 : File = File(name:"nabe") d1.add(f1) d1.add(f2) let d2 : Directory = Directory(name:"fujiwara") let f3 : File = File(name:"nose") d2.add(f3) d1.add(d2) d1.remove() .FNP ෳ਺ͷཁૉ͔ΒͳΔෳ߹ΦϒδΣ ΫτΛ۠ผͳ͘ѻ͑Δ͜ͱͰɺ࠶ ؼతͳߏ଄ͷऔΓѻ͍Λ༰қʹ͢ Δ΋ͷͩΑ ! 配列定義 var shoppingList: Array = ["Eggs", “Milk”] ! 短縮 var shoppingLis1: [String] = ["Eggs", "Milk"] ! 型推論 var shoppingList = ["Eggs", "Milk"] ! ! lazy 必要になるまでインスタンス化されない

Slide 8

Slide 8 text

Facedeパターン class UserDefaultsFacade { class func setObject(value: AnyObject!, forKey defaultName: String!) { let ud : NSUserDefaults = NSUserDefaults.standardUserDefaults() ud.setObject(value, forKey:defaultName) ud.synchronize() } class func objectForKey(defaultName: String!) -> AnyObject! { let ud:NSUserDefaults = NSUserDefaults.standardUserDefaults() return ud.objectForKey(defaultName) } } ! UserDefaultsFacade.setObject("nabe", forKey:"key1") UserDefaultsFacade.objectForKey("key1") .FNP ෳࡶͳॲཧΛγϯϓϧͳ*'Ͱݺͼग़ ͤΔΑ͏ʹ͢ΔύλʔϯͩΑɻ !

Slide 9

Slide 9 text

Adapterパターン protocol Target { func requiredMethod() } ! class Adaptee { func oldMethod() { println(__FUNCTION__) } } ! //継承 class AdapterA: Adaptee, Target { func requiredMethod() { super.oldMethod() } } ! //委譲 class AdapterB: Target { var adaptee : Adaptee = Adaptee() func requiredMethod() { adaptee.oldMethod() } } ! AdapterA().requiredMethod() AdapterB().requiredMethod() .FNP ΠϯλϑΣʔεʹޓ׵ੑͷແ͍Ϋϥ εಉ࢜Λ૊Έ߹ΘͤΔ͜ͱΛ໨త ͱͨ͠ύλʔϯͩΑɻ ! ܧঝΛ࢖ͬͨํ๏ͱҕৡΛ࢖ͬͨ ํ๏͕͋ΔΑɻ ! 4XJGU͸FYUFOUJPOͰ֦ு͢Δ͜ͱ ΋Ͱ͖ΔΑ extension Adaptee: Target { func requiredMethod() { self.oldMethod() } } ! Adaptee().requiredMethod()

Slide 10

Slide 10 text

Bridgeパターン .FNP ʮڮʯͷ໾ׂΛՌͨ͢ύλʔϯͩ Αɻ ! ػೳͷ֦ுͱ࣮૷ͷ֦ுΛ෼͚ͯ ߟ͑ΔύλʔϯͩΑɻ৽͍͠ػೳΛ ௥Ճ αϒΫϥεͰ*'ʹͳ͍ػೳΛ ௥Ճ ͠Α͏ͱͨ͠৔߹ʹɺ࣮૷ʢα ϒΫϥεͰ*'Λ࣮૷ʣΛҙࣝͤͣʹ ػೳ֦ு͕Ͱ͖ΔΑ protocol Car { var engine: Engine {get set} func start() } ! class MiniCooper: Car { var engine: Engine init(engine: Engine) { self.engine = engine } func start() { self.engine.on() } } ! class ToyotaHarrier: Car { var engine: Engine init(engine: Engine) { self.engine = engine } func start() { self.engine.on() } } ! protocol Engine { func on() } ! class Engine1600 : Engine { func on() { println("MiniCooper engine 1600") } } ! class Engine2400 : Engine { func on() { println("ToyotaHarrier engine 2400") } } ! var miniCooper = MiniCooper(engine: Engine1600()) miniCooper.start() ! var toyotaHarrier = ToyotaHarrier(engine: Engine2400()) toyotaHarrier.start() class TurboEngine : Engine { var engine : Engine init(engine: Engine) { self.engine = engine } func on() { turboOn() engine.on() } ! func turboOn() { println("Turbo engine start") } } ! var miniCooperTurbo = MiniCooper(engine: TurboEngine(engine:Engine1600())) miniCooperTurbo.start()

Slide 11

Slide 11 text

Decoratorパターン class RequestHeader { var header: String init(_ header: String) { print("ヘッダー設定処理") self.header = header } } ! class RequestAuthHeader { var requestHeader : RequestHeader init(_ requestHeader : RequestHeader) { self.requestHeader = requestHeader print("Authヘッダーがなければ追加処理") self.requestHeader.header = self.requestHeader.header + "; nabeAuth : lebel99" } ! } ! RequestHeader("nabe : 31") RequestAuthHeader(RequestHeader("nabe : 31")) .FNP %FDPSBUPSύλʔϯ͸ɺ΋ͱͱͳ ΔΦϒδΣΫτʹɺػೳΛ০Γ෇ ͚ͯɺཁٻʹ͋͏ΦϒδΣΫτʹ ࢓্ཱ͍ͯ͛ͯ͘ύλʔϯͩΑɻ ϥούʔύλʔϯͱݺ͹ΕΔ͜ͱ ΋͋ΔΑɻ ! KBWBͩͱOFX#V⒎FSFE0VUQVU4USFBN OFX 'JMF0VUQVU4USFBN lOBCFUYUz ͱ͔ݟͨ͜ͱ͋ΔΑͶ

Slide 12

Slide 12 text

Strategyパターン class Report { ! let strategy: Formatter ! init(_ strategy: Formatter) { self.strategy = strategy } func output(string: String) -> String { return self.strategy.format(title: string) } } ! protocol Formatter { func format(#title: String) -> String } ! class HtmlFormatter : Formatter { func format(#title:String) -> String { //html format処理 print("htmlformat: \(title)") return title } } ! class JsonFormatter : Formatter { func format(#title:String) -> String { //json format処理 print("jsonformat: \(title)") return title } } ! ! Report(HtmlFormatter()).output("string") Report(JsonFormatter()).output("string") .FNP ઓུύλʔϯɻ4USBUFHZύλʔϯ Λར༻͢Δ͜ͱͰɺઓུͷ੾Γସ͑ ΍௥Ճ͕؆୯ʹߦ͑ΔΑ͏ʹͳΔΑɻ ! ! &YUFSOBM1BSBNFUFS/BNFT 4XJGUͰ͸໊લ෇͖ύϥϝλ͕࢖͑ΔΑɻ ΠχγϟϥΠβͱୈೋҾ਺Ҏ߱͸ϥϕϧΛ෇͚ͯݺ ͼग़͢ඞཁ͕͋ΔΑɻ ! ΞϯμʔείΞ @ ͸ɺҾ਺͕ࣗ໌Ͱϥϕϧ͕ඞ ཁͳ͍৔߹ʹ࢖͏Αɻ ! ֎͔Βݟ͑Δϥϕϧͱؔ਺಺Ͱ࢖͏ม਺໊͸ಉ͡৔ ߹͕ଟ͍ͱ͓΋͏ͷͰγϟʔϓʢʣͰ͋ΒΘͤΔ Αɻ

Slide 13

Slide 13 text

Observerパターン var nabe: String = "masataka" { willSet{ print("now: \(nabe)") // set 前の値 print("new: \(newValue)") // set 予定の値 } ! didSet{ print("now: \(nabe)") // set 後の値 print("old: \(oldValue)") // set 前の値 } } ! nabe = "masayasu" .FNP 0CTFSWFSύλʔϯ͸ɺঢ়ଶͷมԽ Λ؍࡯͢Δ͜ͱΛ໨తͱͨ͠ύλʔ ϯͩΑɻ ! $PDPB͸,FZ7BMVF 0CTFSWJOH ,70 ͕0CTFSWFSύ λʔϯͩΑɻ ! KBWBͩͱݴޠ࢓༷Ͱ0CTFSWBCMF ͱ0CTFSWFS Λ࢖࣮ͬͯ૷Ͱ͖Δ Αɻ

Slide 14

Slide 14 text

まとめ ! 無理に当てはめる必要はないけど、 設計に⾏行き詰った時とかに思い出してみてね。

Slide 15

Slide 15 text

おしまい