Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Swiftでデザインパターン10個
Search
Yuji Hato
October 24, 2014
1.5k
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Swiftでデザインパターン10個
Java使いの人にもわかりやすい例にしたよ
Yuji Hato
October 24, 2014
More Decks by Yuji Hato
See All by Yuji Hato
ABEMAにおける 生成AI活用の現在地 / The Current Status of Generative AI at ABEMA
dekatotoro
1
1.2k
ABEMAモバイルアプリ開発のDevOps戦略
dekatotoro
1
740
Multiplatform Engineering Roadmap for the Future
dekatotoro
1
160
Introduction to RIBs
dekatotoro
5
1.4k
継続的な開発スタイル 「AbemaTV iOSアプリを週一で リリースしている話」
dekatotoro
6
4.3k
iOS Adaptive UI - 解像度の異なるデバイスや画面の向きに対応する 最適なレイアウトへ -
dekatotoro
0
540
動画アプリをなめらかに動かす技術 - iOS -
dekatotoro
0
500
5分で学ぶ差分更新とRxDataSources
dekatotoro
0
370
AbemaTV モバイルアプリの開発体制と 開発プロセスの話
dekatotoro
0
290
Featured
See All Featured
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
31
3.2k
How to optimise 3,500 product descriptions for ecommerce in one day using ChatGPT
katarinadahlin
PRO
1
3.7k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
508
140k
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
254
22k
Leveraging Curiosity to Care for An Aging Population
cassininazir
1
350
Digital Projects Gone Horribly Wrong (And the UX Pros Who Still Save the Day) - Dean Schuster
uxyall
1
1.9k
The agentic SEO stack - context over prompts
schlessera
0
840
Building an army of robots
kneath
306
46k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
133
19k
Agile Leadership in an Agile Organization
kimpetersen
PRO
0
190
Practical Orchestrator
shlominoach
191
11k
Reality Check: Gamification 10 Years Later
codingconduct
0
2.2k
Transcript
Swiftでデザインパターン10個 HatoChan
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
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Λ͏Αɻ
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Ӆṭ ͯ͠λΠϓϝιουʹͨ͠ํ͕͔ͬ͜ ͍͍Α
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
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ϓϩύςΟ͕͋ΔΑɻΦϒδΣ ΫτผͳΦϒδΣΫτΛϓϩτλΠϓʹ ͯ͠ಠࣗͷಛΛՃ͍ͯ͘͠ͱ͍͏ߟ͑ ํͷϓϩτλΠϓϕʔεΦϒδΣΫτࢦ ݴޠͩΑɻ
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<FileProtocol> = [] 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<String> = ["Eggs", “Milk”] ! 短縮 var shoppingLis1: [String] = ["Eggs", "Milk"] ! 型推論 var shoppingList = ["Eggs", "Milk"] ! ! lazy 必要になるまでインスタンス化されない
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 ෳࡶͳॲཧΛγϯϓϧͳ*'Ͱݺͼग़ ͤΔΑ͏ʹ͢ΔύλʔϯͩΑɻ !
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 ΠϯλϑΣʔεʹޓੑͷແ͍Ϋϥ εಉ࢜ΛΈ߹ΘͤΔ͜ͱΛత ͱͨ͠ύλʔϯͩΑɻ ! ܧঝΛͬͨํ๏ͱҕৡΛͬͨ ํ๏͕͋ΔΑɻ ! 4XJGUFYUFOUJPOͰ֦ு͢Δ͜ͱ Ͱ͖ΔΑ extension Adaptee: Target { func requiredMethod() { self.oldMethod() } } ! Adaptee().requiredMethod()
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()
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 ͱ͔ݟͨ͜ͱ͋ΔΑͶ
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Ͱ໊લ͖ύϥϝλ͕͑ΔΑɻ ΠχγϟϥΠβͱୈೋҾҎ߱ϥϕϧΛ͚ͯݺ ͼग़͢ඞཁ͕͋ΔΑɻ ! ΞϯμʔείΞ @ ɺҾ͕ࣗ໌Ͱϥϕϧ͕ඞ ཁͳ͍߹ʹ͏Αɻ ! ֎͔Βݟ͑ΔϥϕϧͱؔͰ͏ม໊ಉ͡ ߹͕ଟ͍ͱ͓͏ͷͰγϟʔϓʢʣͰ͋ΒΘͤΔ Αɻ
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 Λ࣮ͬͯͰ͖Δ Αɻ
まとめ ! 無理に当てはめる必要はないけど、 設計に⾏行き詰った時とかに思い出してみてね。
おしまい