From 01afb5e8e8e025828b00105f129fc0d6e6166810 Mon Sep 17 00:00:00 2001 From: ochococo Date: Mon, 21 Nov 2016 21:25:35 +0100 Subject: [PATCH 01/66] Add Flyweight by DavydLiu. --- Design-Patterns.playground.zip | Bin 143945 -> 144426 bytes .../Contents.swift | 64 +++++++++ README.md | 123 +++++++++++++++++- generate-playground.sh | 4 +- source/structural/flyweight.swift | 64 +++++++++ 5 files changed, 249 insertions(+), 6 deletions(-) create mode 100644 source/structural/flyweight.swift diff --git a/Design-Patterns.playground.zip b/Design-Patterns.playground.zip index 80a2654d6a0dd3deafe4f8c2a561737e6664a5a5..2d9df3c1ab71c97a75e088bd1a888a28eef91ece 100644 GIT binary patch delta 3490 zcmZWsby(C}w`P8HA4&xV1Zf5kkQf+BRA%Vz6r{UL7)fav1P2Bw=|<@i7?e;_=|%=c zIuuj{K9KXBd+xpadDh-*t#_?=?`Qw@u6`Uz*%}FzmMT608Q#SrDD_oFQHc{=oMG^K zIH*L3=EDC2{=JDl1zl%F=T?BOGG8>(pQlOwG^(WUu-cqQkIzlzpQ6U7o1j?P|HmT# z-vUPTBVK@#;@?D#?yjI<;Ljt_+wLIPrI(uo5<%DS0j%hqBoGO~K$)*{V~hu=lJ;M4 z2m}D5w~|0)mvCwXD3Ih2+(?rEivOGPoXC*sqTOa?B%hZY53iRSogD$|2P#U~6P$=Nzi)b}1`I?l_g@L1RS_HBPeoDA({hlm zJ>PGnIMuA&4|?mZ{%pYI8XdtTgo~sE_P596 zhl5FpbR;dNHJiAj>_kk`Ak9SOT{Efi@iX9B)LlTrsT;&8bR(n7`ZWP`K*FA>Ylau| zC5GO54aPXY!|Z0zDWp;=6gF`$3CZuQ+DBNDJVFxoyJd-N49@~eR|wXkkli`ln#CU` zN7Oc83{(Hn%!BURBrN=7L0VFpZ}pRAtr%%=e1BW@5J}+M+8b31f{xdz$Gh+wtR*>X zH@5VueqfmFUW$yr%Q9;}-Ii!I%q+V0CaL5|JVwxgAW1_tx`vJ4i6T@m zeFZ~~u_+m@kqBcFe+0cMTIKI#A^Qx}fsZs113Ga1FDk-%r zQdmF~bd@v4!o#{6gy1{4nxMK;Di^`p`#Lc(x!&?uy9nmWmnTd{waQ*_dMi8}5_O!S z2}n&@lAYA)WPZm|fP57v;j{mIXQiXkObQz$$)V;^59srzDYeODnOnQWa}_}D1B(@v zpO(aQemo5h@hcYNkK5#pQnz0}fmUznc!;((2-^Dp;25x*pC%D*I9TXeUv(7D2xup~ zzlHbA94MGgVw|*FG>%HCS{g?PtsE}mNXRHln;jp!v9xQ8Bc-l%(p*VPsDSF~-GdA` z9RKC5ohN2_XN<3BT@*F_s38rk*!G(vo~=hR`5D{Hn+CFAPApyp8b#sM#Wix5<|8jU zE}cHQ7;MSrcze{rDxvHef^Z5(VI($g!l$4p8Ez=H168S5<3^nxqzSjq@CEeE*mzVx9#Pao<7rjhJDfm44*_r!jq=O zBPSh9azJ8P5|&jk7TbK&JZB20VBt|f`{T$Hf5Ta8*9`ob81-l--%+@g`Fn32@ zJCRYoP8L-tv?k};KpD&6khbQPIYz(JbL&lo3QZ8IFp&)~u17DHv_a5U&-efN8r! zF>KT^-RDven=-*NnD}4=j~x`E;5WU1C!bQVndoX&;R7PRX-7!9&TcBi_M`b_DHG8= zh$7GJcnWFFnXpkJo1%=BrlN*#qQ;24erFwTapz(lCakI^3?})B4M8wQCR6*JBH8Ae zoi%3d%&c{gQAi~9Y8 zD>3K5ny6pY!HL1a95%e>lZN#gz>#Rm&;*;KW9nL)>SwKuBsZ8(-;bQFDcSz{=n*!o%uSqep@?1+a3egdv!WG zyNwmWUUja1zC*FAR}+|tX=d^E$TOv7@>PDB2aQK3h*hjkG%W2uX-?w&rlR%ER)F&f z^4Ed9HBj{geRsr})X~7Iz>;HKekq8{dv_|%7>=@=A?4Ak4~1)d*oxjeNb{^RYeyyq zdJ{=WcW0hb1nJjDd5*BWH}F}+rdkT+J|D~&+2#kAd1nfhavRfB?jqL^b%K(vbT&I5 zL}UWUNUH_Bx^Fu}qmsuPNa`ue$S0nrR^<^8DmlhIvYI!`%!lb`aOo%0T3ChW4lY|U z2g8h|)MY8gJqrSo3ipNFDmx!~H;xC%jnp!Fxh`<;uI6fr4$g(TLC*aq%3}6(qxNAp8LV zW2v=WSfIcFl>dZ*QBkH5VK|MQ-x(!81UC~lwl;0iZD4MB91aaO(uLUZXkQbhg7s0y zJ0tX+uY6-(@7$lN&c%j~itMnv4Ug&(oB~t1D;;J2B(!1VxrRx`z8fQchb%{X+7UZ# zgc9K&)uJe67^F{WzBS#WM|!fKFy*&CgGnrhR^py#6{Wo(&x{EChZE{TGSvB}T8S1r6 z7I0@T^g%prQIELm7v$HHg6H}@^G>VUCJM&vyRh8*mWprpfx9kj_C!)LJ}$v*w&oeL zWO<#=_c*(C2YZQgYV>MZeDR}7gDdq+PDUK$#g0;krzN+_wBr<>#uL=wE90ut-705KVV*DC|J&`X5on2Lt| zb;7u*;T2KrRAC=K=|5(=4PJ(bV!|MyscK9}Aim)g39AE0X_&j8(!xzy|;d?+xA+0| zOF#|+`2GPJ8zI01=&}YS2-yGMNq|TQaAv!hc`8?$Zfl*7G6Cmyab7IYxfO(kV$did z;2|KBiSFVC80U4n5e*#+c{7nD>%v4^&cEW%xfT;Q>pu2$i(LS$1^b~(s@&3Zw Zx~^~2VM{fWC delta 3018 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 CoffeeFlavor { + if flavors.indexForKey(flavor) == nil { + flavors[flavor] = CoffeeFlavor(flavor: flavor) + } + return flavors[flavor]! + } +} + +class CoffeeShop { + private var orders: [Int: CoffeeFlavor] = [:] + private var menu = Menu() + + func takeOrder(#flavor: String, table: Int) { + orders[table] = menu.lookup(flavor) + } + + func serve() { + for (table, flavor) in orders { + println("Serving \(flavor) to table \(table)") + } + } +} +/*: +### Usage +*/ +let coffeeShop = CoffeeShop() + +coffeeShop.takeOrder(flavor: "Cappuccino", table: 1) +coffeeShop.takeOrder(flavor: "Frappe", table: 3); +coffeeShop.takeOrder(flavor: "Espresso", table: 2); +coffeeShop.takeOrder(flavor: "Frappe", table: 15); +coffeeShop.takeOrder(flavor: "Cappuccino", table: 10); +coffeeShop.takeOrder(flavor: "Frappe", table: 8); +coffeeShop.takeOrder(flavor: "Espresso", table: 7); +coffeeShop.takeOrder(flavor: "Cappuccino", table: 4); +coffeeShop.takeOrder(flavor: "Espresso", table: 9); +coffeeShop.takeOrder(flavor: "Frappe", table: 12); +coffeeShop.takeOrder(flavor: "Cappuccino", table: 13); +coffeeShop.takeOrder(flavor: "Espresso", table: 5); + +coffeeShop.serve() +/*: ☔ Protection Proxy ------------------ diff --git a/README.md b/README.md index b68bb92..54c3c35 100644 --- a/README.md +++ b/README.md @@ -5,14 +5,19 @@ A short cheat-sheet with Xcode 7.3 Playground ([Design-Patterns.playground.zip]( 👷 Project maintained by: [@nsmeme](http://twitter.com/nsmeme) (Oktawian Chojnacki) -⚠️ See my newest project: [OOD-Principles-In-Swift](https://github.com/ochococo/OOD-Principles-In-Swift) - ## Table of Contents * [Behavioral](#behavioral) * [Creational](#creational) * [Structural](#structural) + +```swift + Behavioral | + [Creational](Creational) | + [Structural](Structural) +``` + Behavioral ========== @@ -123,6 +128,9 @@ atm.canWithdraw(30) // Can withdraw - 1x20, 2x10 >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Chain-Of-Responsibility) +```swift + +``` 👫 Command ---------- @@ -289,6 +297,9 @@ var result = expression?.evaluate(intContext) >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Interpreter) +```swift + +``` 🍫 Iterator ----------- @@ -396,6 +407,9 @@ user0.send("Hello") // user1 receives message >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Mediator) +```swift + +``` 💾 Memento ---------- @@ -534,6 +548,9 @@ testChambers.testChamberNumber++ >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Observer) +```swift + +``` 🐉 State --------- @@ -602,6 +619,10 @@ context.changeStateToUnauthorized() >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-State) +```swift + +``` + 💡 Strategy ----------- @@ -654,6 +675,9 @@ upper.printString("O tempora, o mores!") >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Strategy) +```swift + +``` 🏃 Visitor ---------- @@ -710,6 +734,12 @@ names >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Visitor) +```swift + + [Behavioral](Behavioral) | + Creational | + [Structural](Structural) +``` Creational ========== @@ -732,6 +762,9 @@ The "family" of objects created by the factory are determined at run-time. ### Example +```swift + +``` Protocols @@ -864,6 +897,9 @@ let deathStar = DeathStar(builder:empire) >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Builder) +```swift + +``` 🏭 Factory Method ----------------- @@ -973,6 +1009,9 @@ Eduardo.name = "Eduardo" >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Prototype) +```swift + +``` 💍 Singleton ------------ @@ -999,7 +1038,9 @@ class DeathStarSuperlaser { ```swift let laser = DeathStarSuperlaser.sharedInstance - + [Behavioral](Behavioral) | + [Creational](Creational) | + Structural ``` Structural @@ -1079,6 +1120,9 @@ oldFormat.angleV >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Adapter) +```swift + +``` 🌉 Bridge ---------- @@ -1141,6 +1185,9 @@ The composite pattern is used to create hierarchical, recursive tree structures ### Example +```swift + +``` Component @@ -1313,6 +1360,76 @@ Eternal.setObject("Disconnect me. I’d rather be nothing", forKey:"Bishop") Eternal.objectForKey("Bishop") ``` +## 🍃 Flyweight +The flyweight pattern is used to minimize memory usage or computational expenses by sharing as much as possible with other similar objects. +### Example + +```swift + +// Instances of CoffeeFlavour will be the Flyweights +class CoffeeFlavor : Printable { + var flavor: String + var description: String { + get { + return flavor + } + } + + init(flavor: String) { + self.flavor = flavor + } +} + +// Menu acts as a factory and cache for CoffeeFlavour flyweight objects +class Menu { + private var flavors: [String: CoffeeFlavor] = [:] + + func lookup(flavor: String) -> CoffeeFlavor { + if flavors.indexForKey(flavor) == nil { + flavors[flavor] = CoffeeFlavor(flavor: flavor) + } + return flavors[flavor]! + } +} + +class CoffeeShop { + private var orders: [Int: CoffeeFlavor] = [:] + private var menu = Menu() + + func takeOrder(#flavor: String, table: Int) { + orders[table] = menu.lookup(flavor) + } + + func serve() { + for (table, flavor) in orders { + println("Serving \(flavor) to table \(table)") + } + } +} +``` + +### Usage + +```swift + +let coffeeShop = CoffeeShop() + +coffeeShop.takeOrder(flavor: "Cappuccino", table: 1) +coffeeShop.takeOrder(flavor: "Frappe", table: 3); +coffeeShop.takeOrder(flavor: "Espresso", table: 2); +coffeeShop.takeOrder(flavor: "Frappe", table: 15); +coffeeShop.takeOrder(flavor: "Cappuccino", table: 10); +coffeeShop.takeOrder(flavor: "Frappe", table: 8); +coffeeShop.takeOrder(flavor: "Espresso", table: 7); +coffeeShop.takeOrder(flavor: "Cappuccino", table: 4); +coffeeShop.takeOrder(flavor: "Espresso", table: 9); +coffeeShop.takeOrder(flavor: "Frappe", table: 12); +coffeeShop.takeOrder(flavor: "Cappuccino", table: 13); +coffeeShop.takeOrder(flavor: "Espresso", table: 5); + +coffeeShop.serve() +``` + ☔ Protection Proxy ------------------ diff --git a/generate-playground.sh b/generate-playground.sh index 045c657..262df87 100755 --- a/generate-playground.sh +++ b/generate-playground.sh @@ -1,7 +1,5 @@ #!/bin/bash -rm ./contents.swift - cleanThisMessForReadme () { FILENAME=$1 @@ -33,4 +31,4 @@ zip -r -X Design-Patterns.playground.zip ./Design-Patterns.playground rm ./Behavioral.swift rm ./Creational.swift rm ./Structural.swift -rm ./contents.swift \ No newline at end of file +rm ./contents.swift diff --git a/source/structural/flyweight.swift b/source/structural/flyweight.swift new file mode 100644 index 0000000..f893619 --- /dev/null +++ b/source/structural/flyweight.swift @@ -0,0 +1,64 @@ +/*: +## 🍃 Flyweight +The flyweight pattern is used to minimize memory usage or computational expenses by sharing as much as possible with other similar objects. +### Example +*/ +// Instances of CoffeeFlavour will be the Flyweights +class CoffeeFlavor : Printable { + var flavor: String + var description: String { + get { + return flavor + } + } + + init(flavor: String) { + self.flavor = flavor + } +} + +// Menu acts as a factory and cache for CoffeeFlavour flyweight objects +class Menu { + private var flavors: [String: CoffeeFlavor] = [:] + + func lookup(flavor: String) -> CoffeeFlavor { + if flavors.indexForKey(flavor) == nil { + flavors[flavor] = CoffeeFlavor(flavor: flavor) + } + return flavors[flavor]! + } +} + +class CoffeeShop { + private var orders: [Int: CoffeeFlavor] = [:] + private var menu = Menu() + + func takeOrder(#flavor: String, table: Int) { + orders[table] = menu.lookup(flavor) + } + + func serve() { + for (table, flavor) in orders { + println("Serving \(flavor) to table \(table)") + } + } +} +/*: +### Usage +*/ +let coffeeShop = CoffeeShop() + +coffeeShop.takeOrder(flavor: "Cappuccino", table: 1) +coffeeShop.takeOrder(flavor: "Frappe", table: 3); +coffeeShop.takeOrder(flavor: "Espresso", table: 2); +coffeeShop.takeOrder(flavor: "Frappe", table: 15); +coffeeShop.takeOrder(flavor: "Cappuccino", table: 10); +coffeeShop.takeOrder(flavor: "Frappe", table: 8); +coffeeShop.takeOrder(flavor: "Espresso", table: 7); +coffeeShop.takeOrder(flavor: "Cappuccino", table: 4); +coffeeShop.takeOrder(flavor: "Espresso", table: 9); +coffeeShop.takeOrder(flavor: "Frappe", table: 12); +coffeeShop.takeOrder(flavor: "Cappuccino", table: 13); +coffeeShop.takeOrder(flavor: "Espresso", table: 5); + +coffeeShop.serve() From 51546fd5230441a46acba8c3ec1eff37d04bd3d7 Mon Sep 17 00:00:00 2001 From: ochococo Date: Mon, 21 Nov 2016 21:26:13 +0100 Subject: [PATCH 02/66] Ignore `UserInterfaceState.xcuserstate`. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 697f316..8cdb2b6 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ # Pods/ .DS_Store +UserInterfaceState.xcuserstate From 3f2de972784a7756ae27b2e1e9e48e6de1abe25c Mon Sep 17 00:00:00 2001 From: ochococo Date: Mon, 21 Nov 2016 23:06:29 +0100 Subject: [PATCH 03/66] Behavioral Patterns updated to Swift2. --- .../Contents.swift | 364 ++++++++++-------- .../behavioral/chain_of_responsibility.swift | 57 +-- source/behavioral/interpreter.swift | 89 +++-- source/behavioral/iterator.swift | 34 +- source/behavioral/mediator.swift | 62 ++- source/behavioral/memento.swift | 74 ++-- source/behavioral/observer.swift | 22 +- source/behavioral/state.swift | 24 +- source/behavioral/strategy.swift | 34 +- source/footer.swift | 4 +- source/header.swift | 8 +- 11 files changed, 414 insertions(+), 358 deletions(-) diff --git a/Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift b/Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift index ea11058..0250790 100644 --- a/Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift +++ b/Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift @@ -20,6 +20,7 @@ The chain of responsibility pattern is used to process varied requests, each of ### Example: */ class MoneyPile { + let value: Int var quantity: Int var nextPile: MoneyPile? @@ -30,30 +31,32 @@ class MoneyPile { self.nextPile = nextPile } - func canWithdraw(v: Int) -> Bool { + func canWithdraw(amount: Int) -> Bool { - var v = v + var amount = amount func canTakeSomeBill(want: Int) -> Bool { return (want / self.value) > 0 } - var q = self.quantity + var quantity = self.quantity - while canTakeSomeBill(v) { + while canTakeSomeBill(want: amount) { - if q == 0 { + if quantity == 0 { break } - v -= self.value - q -= 1 + amount -= self.value + quantity -= 1 } - if v == 0 { + guard amount > 0 else { return true - } else if let next = self.nextPile { - return next.canWithdraw(v) + } + + if let next = self.nextPile { + return next.canWithdraw(amount: amount) } return false @@ -81,8 +84,8 @@ class ATM { self.ten = ten } - func canWithdraw(value: Int) -> String { - return "Can withdraw: \(self.startPile.canWithdraw(value))" + func canWithdraw(amount: Int) -> String { + return "Can withdraw: \(self.startPile.canWithdraw(amount: amount))" } } /*: @@ -96,10 +99,10 @@ let hundred = MoneyPile(value: 100, quantity: 1, nextPile: fifty) // Build ATM. var atm = ATM(hundred: hundred, fifty: fifty, twenty: twenty, ten: ten) -atm.canWithdraw(310) // Cannot because ATM has only 300 -atm.canWithdraw(100) // Can withdraw - 1x100 -atm.canWithdraw(165) // Cannot withdraw because ATM doesn't has bill with value of 5 -atm.canWithdraw(30) // Can withdraw - 1x20, 2x10 +atm.canWithdraw(amount: 310) // Cannot because ATM has only 300 +atm.canWithdraw(amount: 100) // Can withdraw - 1x100 +atm.canWithdraw(amount: 165) // Cannot withdraw because ATM doesn't has bill with value of 5 +atm.canWithdraw(amount: 30) // Can withdraw - 1x20, 2x10 /*: >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Chain-Of-Responsibility) */ @@ -173,87 +176,86 @@ The interpreter pattern is used to evaluate sentences in a language. ### Example */ -protocol IntegerExp { - func evaluate(context: IntegerContext) -> Int - func replace(character: Character, integerExp: IntegerExp) -> IntegerExp - func copy() -> IntegerExp +protocol IntegerExpression { + func evaluate(_ context: IntegerContext) -> Int + func replace(character: Character, integerExpression: IntegerExpression) -> IntegerExpression + func copied() -> IntegerExpression } -class IntegerContext { +final class IntegerContext { private var data: [Character:Int] = [:] func lookup(name: Character) -> Int { return self.data[name]! } - func assign(integerVarExp: IntegerVarExp, value: Int) { - self.data[integerVarExp.name] = value + func assign(expression: IntegerVariableExpression, value: Int) { + self.data[expression.name] = value } } -class IntegerVarExp: IntegerExp { +final class IntegerVariableExpression: IntegerExpression { let name: Character init(name: Character) { self.name = name } - func evaluate(context: IntegerContext) -> Int { - return context.lookup(self.name) + func evaluate(_ context: IntegerContext) -> Int { + return context.lookup(name: self.name) } - func replace(name: Character, integerExp: IntegerExp) -> IntegerExp { + func replace(character name: Character, integerExpression: IntegerExpression) -> IntegerExpression { if name == self.name { - return integerExp.copy() + return integerExpression.copied() } else { - return IntegerVarExp(name: self.name) + return IntegerVariableExpression(name: self.name) } } - func copy() -> IntegerExp { - return IntegerVarExp(name: self.name) + func copied() -> IntegerExpression { + return IntegerVariableExpression(name: self.name) } } -class AddExp: IntegerExp { - private var operand1: IntegerExp - private var operand2: IntegerExp +final class AddExpression: IntegerExpression { + private var operand1: IntegerExpression + private var operand2: IntegerExpression - init(op1: IntegerExp, op2: IntegerExp) { + init(op1: IntegerExpression, op2: IntegerExpression) { self.operand1 = op1 self.operand2 = op2 } - func evaluate(context: IntegerContext) -> Int { + func evaluate(_ context: IntegerContext) -> Int { return self.operand1.evaluate(context) + self.operand2.evaluate(context) } - func replace(character: Character, integerExp: IntegerExp) -> IntegerExp { - return AddExp(op1: operand1.replace(character, integerExp: integerExp), - op2: operand2.replace(character, integerExp: integerExp)) + func replace(character: Character, integerExpression: IntegerExpression) -> IntegerExpression { + return AddExpression(op1: operand1.replace(character: character, integerExpression: integerExpression), + op2: operand2.replace(character: character, integerExpression: integerExpression)) } - func copy() -> IntegerExp { - return AddExp(op1: self.operand1, op2: self.operand2) + func copied() -> IntegerExpression { + return AddExpression(op1: self.operand1, op2: self.operand2) } } /*: ### Usage */ -var expression: IntegerExp? -var intContext = IntegerContext() +var context = IntegerContext() -var a = IntegerVarExp(name: "A") -var b = IntegerVarExp(name: "B") -var c = IntegerVarExp(name: "C") +var a = IntegerVariableExpression(name: "A") +var b = IntegerVariableExpression(name: "B") +var c = IntegerVariableExpression(name: "C") -expression = AddExp(op1: a, op2: AddExp(op1: b, op2: c)) // a + (b + c) +var expression = AddExpression(op1: a, op2: AddExpression(op1: b, op2: c)) // a + (b + c) -intContext.assign(a, value: 2) -intContext.assign(b, value: 1) -intContext.assign(c, value: 3) +context.assign(expression: a, value: 2) +context.assign(expression: b, value: 1) +context.assign(expression: c, value: 3) -var result = expression?.evaluate(intContext) +var result = expression.evaluate(context) /*: >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Interpreter) */ @@ -265,22 +267,38 @@ The iterator pattern is used to provide a standard interface for traversing a co ### Example: */ -struct NovellasCollection { - let novellas: [T] +struct Novella { + let name: String } -extension NovellasCollection: SequenceType { - typealias Generator = AnyGenerator - - func generate() -> AnyGenerator { - var i = 0 - return AnyGenerator { i += 1; return i >= self.novellas.count ? nil : self.novellas[i] } +struct Novellas { + let novellas: [Novella] +} + +struct NovellasIterator: IteratorProtocol { + + private var current = 0 + private let novellas: [Novella] + + init(novellas: [Novella]) { + self.novellas = novellas + } + + mutating func next() -> Novella? { + defer { current += 1 } + return novellas.count > current ? novellas[current] : nil + } +} + +extension Novellas: Sequence { + func makeIterator() -> NovellasIterator { + return NovellasIterator(novellas: novellas) } } /*: ### Usage */ -let greatNovellas = NovellasCollection(novellas:["Mist"]) +let greatNovellas = Novellas(novellas: [Novella(name: "The Mist")] ) for novella in greatNovellas { print("I've read: \(novella)") @@ -294,61 +312,54 @@ The mediator pattern is used to reduce coupling between classes that communicate ### Example */ -class Colleague { +struct Programmer { + let name: String - let mediator: Mediator - init(name: String, mediator: Mediator) { + init(name: String) { self.name = name - self.mediator = mediator - } - - func send(message: String) { - mediator.send(message, colleague: self) } func receive(message: String) { - assert(false, "Method should be overriden") + print("\(name) received: \(message)") } } -protocol Mediator { - func send(message: String, colleague: Colleague) +protocol MessageSending { + func send(message: String) } -class MessageMediator: Mediator { - private var colleagues: [Colleague] = [] +final class MessageMediator: MessageSending { + + private var recipients: [Programmer] = [] - func addColleague(colleague: Colleague) { - colleagues.append(colleague) + func add(recipient: Programmer) { + recipients.append(recipient) } - func send(message: String, colleague: Colleague) { - for c in colleagues { - if c !== colleague { //for simplicity we compare object references - c.receive(message) - } + func send(message: String) { + for recipient in recipients { + recipient.receive(message: message) } } } -class ConcreteColleague: Colleague { - override func receive(message: String) { - print("Colleague \(name) received: \(message)") - } -} - /*: ### Usage */ +func spamMonster(message: String, worker: MessageSending) { + worker.send(message: message) +} + let messagesMediator = MessageMediator() -let user0 = ConcreteColleague(name: "0", mediator: messagesMediator) -let user1 = ConcreteColleague(name: "1", mediator: messagesMediator) -messagesMediator.addColleague(user0) -messagesMediator.addColleague(user1) -user0.send("Hello") // user1 receives message +let user0 = Programmer(name: "Linus Torvalds") +let user1 = Programmer(name: "Avadis 'Avie' Tevanian") +messagesMediator.add(recipient: user0) +messagesMediator.add(recipient: user1) + +spamMonster(message: "I'd Like to Add you to My Professional Network", worker: messagesMediator) /*: >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Mediator) */ @@ -360,66 +371,84 @@ The memento pattern is used to capture the current state of an object and store ### Example */ -typealias Memento = Dictionary - -let DPMementoKeyChapter = "com.valve.halflife.chapter" -let DPMementoKeyWeapon = "com.valve.halflife.weapon" -let DPMementoGameState = "com.valve.halflife.state" +typealias Memento = NSDictionary /*: Originator */ -class GameState { - var chapter: String = "" - var weapon: String = "" - func toMemento() -> Memento { - return [ DPMementoKeyChapter:chapter, DPMementoKeyWeapon:weapon ] +protocol MementoConvertible { + var memento: Memento { get } + init?(memento: Memento) +} + +struct GameState: MementoConvertible { + + private struct Keys { + static let chapter = "com.valve.halflife.chapter" + static let weapon = "com.valve.halflife.weapon" + } + + var chapter: String + var weapon: String + + init(chapter: String, weapon: String) { + self.chapter = chapter + self.weapon = weapon + } + + init?(memento: Memento) { + guard let mementoChapter = memento[Keys.chapter] as? String, + let mementoWeapon = memento[Keys.weapon] as? String else { + return nil + } + + chapter = mementoChapter + weapon = mementoWeapon } - func restoreFromMemento(memento: Memento) { - chapter = memento[DPMementoKeyChapter] as? String ?? "n/a" - weapon = memento[DPMementoKeyWeapon] as? String ?? "n/a" + var memento: Memento { + return [ Keys.chapter: chapter, Keys.weapon: weapon ] } } + + /*: Caretaker */ enum CheckPoint { - static func saveState(memento: Memento, keyName: String = DPMementoGameState) { - let defaults = NSUserDefaults.standardUserDefaults() - defaults.setObject(memento, forKey: keyName) + static func save(_ state: MementoConvertible, saveName: String) { + let defaults = UserDefaults.standard + defaults.set(state.memento, forKey: saveName) defaults.synchronize() } - static func restorePreviousState(keyName keyName: String = DPMementoGameState) -> Memento { - let defaults = NSUserDefaults.standardUserDefaults() + static func restore(saveName: String) -> Memento? { + let defaults = UserDefaults.standard - return defaults.objectForKey(keyName) as? Memento ?? Memento() + return defaults.object(forKey: saveName) as? Memento } } /*: ### Usage */ -var gameState = GameState() -gameState.restoreFromMemento(CheckPoint.restorePreviousState()) - -gameState.chapter = "Black Mesa Inbound" -gameState.weapon = "Crowbar" -CheckPoint.saveState(gameState.toMemento()) +var gameState = GameState(chapter: "Black Mesa Inbound", weapon: "Crowbar") gameState.chapter = "Anomalous Materials" gameState.weapon = "Glock 17" -gameState.restoreFromMemento(CheckPoint.restorePreviousState()) +CheckPoint.save(gameState, saveName: "gameState1") gameState.chapter = "Unforeseen Consequences" gameState.weapon = "MP5" -CheckPoint.saveState(gameState.toMemento(), keyName: "gameState2") +CheckPoint.save(gameState, saveName: "gameState2") gameState.chapter = "Office Complex" gameState.weapon = "Crossbow" -CheckPoint.saveState(gameState.toMemento()) +CheckPoint.save(gameState, saveName: "gameState3") -gameState.restoreFromMemento(CheckPoint.restorePreviousState(keyName: "gameState2")) +if let memento = CheckPoint.restore(saveName: "gameState1") { + let finalState = GameState(memento: memento) + dump(finalState) +} /*: 👓 Observer @@ -431,32 +460,34 @@ Other objects subscribe to be immediately notified of any changes. ### Example */ protocol PropertyObserver : class { - func willChangePropertyName(propertyName:String, newPropertyValue:AnyObject?) - func didChangePropertyName(propertyName:String, oldPropertyValue:AnyObject?) + func willChange(propertyName: String, newPropertyValue: Any?) + func didChange(propertyName: String, oldPropertyValue: Any?) } class TestChambers { weak var observer:PropertyObserver? + private let testChamberNumberName = "testChamberNumber" + var testChamberNumber: Int = 0 { willSet(newValue) { - observer?.willChangePropertyName("testChamberNumber", newPropertyValue:newValue) + observer?.willChange(propertyName: testChamberNumberName, newPropertyValue: newValue) } didSet { - observer?.didChangePropertyName("testChamberNumber", oldPropertyValue:oldValue) + observer?.didChange(propertyName: testChamberNumberName, oldPropertyValue: oldValue) } } } class Observer : PropertyObserver { - func willChangePropertyName(propertyName: String, newPropertyValue: AnyObject?) { + func willChange(propertyName: String, newPropertyValue: Any?) { if newPropertyValue as? Int == 1 { print("Okay. Look. We both said a lot of things that you're going to regret.") } } - func didChangePropertyName(propertyName: String, oldPropertyValue: AnyObject?) { + func didChange(propertyName: String, oldPropertyValue: Any?) { if oldPropertyValue as? Int == 0 { print("Sorry about the mess. I've really let the place go since you killed me.") } @@ -468,7 +499,7 @@ class Observer : PropertyObserver { var observerInstance = Observer() var testChambers = TestChambers() testChambers.observer = observerInstance -testChambers.testChamberNumber++ +testChambers.testChamberNumber += 1 /*: >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Observer) */ @@ -481,18 +512,18 @@ The pattern allows the class for an object to apparently change at run-time. ### Example */ -class Context { +final class Context { private var state: State = UnauthorizedState() var isAuthorized: Bool { - get { return state.isAuthorized(self) } + get { return state.isAuthorized(context: self) } } var userId: String? { - get { return state.userId(self) } + get { return state.userId(context: self) } } - func changeStateToAuthorized(userId userId: String) { + func changeStateToAuthorized(userId: String) { state = AuthorizedState(userId: userId) } @@ -525,12 +556,12 @@ class AuthorizedState: State { /*: ### Usage */ -let context = Context() -(context.isAuthorized, context.userId) -context.changeStateToAuthorized(userId: "admin") -(context.isAuthorized, context.userId) // now logged in as "admin" -context.changeStateToUnauthorized() -(context.isAuthorized, context.userId) +let userContext = Context() +(userContext.isAuthorized, userContext.userId) +userContext.changeStateToAuthorized(userId: "admin") +(userContext.isAuthorized, userContext.userId) // now logged in as "admin" +userContext.changeStateToUnauthorized() +(userContext.isAuthorized, userContext.userId) /*: >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-State) */ @@ -543,15 +574,15 @@ The strategy pattern is used to create an interchangeable family of algorithms f ### Example */ protocol PrintStrategy { - func printString(string: String) -> String + func print(_ string: String) -> String } -class Printer { +final class Printer { - let strategy: PrintStrategy + private let strategy: PrintStrategy - func printString(string: String) -> String { - return self.strategy.printString(string) + func print(_ string: String) -> String { + return self.strategy.print(string) } init(strategy: PrintStrategy) { @@ -559,25 +590,25 @@ class Printer { } } -class UpperCaseStrategy : PrintStrategy { - func printString(string:String) -> String { - return string.uppercaseString +final class UpperCaseStrategy: PrintStrategy { + func print(_ string: String) -> String { + return string.uppercased() } } -class LowerCaseStrategy : PrintStrategy { - func printString(string:String) -> String { - return string.lowercaseString +final class LowerCaseStrategy: PrintStrategy { + func print(_ string:String) -> String { + return string.lowercased() } } /*: ### Usage */ -var lower = Printer(strategy:LowerCaseStrategy()) -lower.printString("O tempora, o mores!") +var lower = Printer(strategy: LowerCaseStrategy()) +lower.print("O tempora, o mores!") -var upper = Printer(strategy:UpperCaseStrategy()) -upper.printString("O tempora, o mores!") +var upper = Printer(strategy: UpperCaseStrategy()) +upper.print("O tempora, o mores!") /*: >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Strategy) */ @@ -590,31 +621,32 @@ The visitor pattern is used to separate a relatively complex set of structured d ### Example */ protocol PlanetVisitor { - func visit(planet: PlanetAlderaan) - func visit(planet: PlanetCoruscant) - func visit(planet: PlanetTatooine) + func visit(_ planet: PlanetAlderaan) + func visit(_ planet: PlanetCoruscant) + func visit(_ planet: PlanetTatooine) } protocol Planet { - func accept(visitor: PlanetVisitor) + func accept(_ visitor: PlanetVisitor) } -class PlanetAlderaan: Planet { - func accept(visitor: PlanetVisitor) { visitor.visit(self) } +final class PlanetAlderaan: Planet { + func accept(_ visitor: PlanetVisitor) { visitor.visit(self) } } -class PlanetCoruscant: Planet { - func accept(visitor: PlanetVisitor) { visitor.visit(self) } +final class PlanetCoruscant: Planet { + func accept(_ visitor: PlanetVisitor) { visitor.visit(self) } } -class PlanetTatooine: Planet { - func accept(visitor: PlanetVisitor) { visitor.visit(self) } +final class PlanetTatooine: Planet { + func accept(_ visitor: PlanetVisitor) { visitor.visit(self) } } -class NameVisitor: PlanetVisitor { +final class NameVisitor: PlanetVisitor { + var name = "" - func visit(planet: PlanetAlderaan) { name = "Alderaan" } - func visit(planet: PlanetCoruscant) { name = "Coruscant" } - func visit(planet: PlanetTatooine) { name = "Tatooine" } + func visit(_ planet: PlanetAlderaan) { name = "Alderaan" } + func visit(_ planet: PlanetCoruscant) { name = "Coruscant" } + func visit(_ planet: PlanetTatooine) { name = "Tatooine" } } /*: ### Usage diff --git a/source/behavioral/chain_of_responsibility.swift b/source/behavioral/chain_of_responsibility.swift index b2909b1..7ea5764 100644 --- a/source/behavioral/chain_of_responsibility.swift +++ b/source/behavioral/chain_of_responsibility.swift @@ -6,60 +6,63 @@ The chain of responsibility pattern is used to process varied requests, each of ### Example: */ -class MoneyPile { +final class MoneyPile { + let value: Int var quantity: Int var nextPile: MoneyPile? - + init(value: Int, quantity: Int, nextPile: MoneyPile?) { self.value = value self.quantity = quantity self.nextPile = nextPile } - - func canWithdraw(v: Int) -> Bool { - var v = v + func canWithdraw(amount: Int) -> Bool { + + var amount = amount func canTakeSomeBill(want: Int) -> Bool { return (want / self.value) > 0 } - - var q = self.quantity - while canTakeSomeBill(v) { + var quantity = self.quantity - if q == 0 { + while canTakeSomeBill(want: amount) { + + if quantity == 0 { break } - v -= self.value - q -= 1 + amount -= self.value + quantity -= 1 } - if v == 0 { + guard amount > 0 else { return true - } else if let next = self.nextPile { - return next.canWithdraw(v) + } + + if let next = self.nextPile { + return next.canWithdraw(amount: amount) } return false } } -class ATM { +final class ATM { private var hundred: MoneyPile private var fifty: MoneyPile private var twenty: MoneyPile private var ten: MoneyPile - + private var startPile: MoneyPile { return self.hundred } - - init(hundred: MoneyPile, - fifty: MoneyPile, - twenty: MoneyPile, + + init(hundred: MoneyPile, + fifty: MoneyPile, + twenty: MoneyPile, ten: MoneyPile) { self.hundred = hundred @@ -67,9 +70,9 @@ class ATM { self.twenty = twenty self.ten = ten } - - func canWithdraw(value: Int) -> String { - return "Can withdraw: \(self.startPile.canWithdraw(value))" + + func canWithdraw(amount: Int) -> String { + return "Can withdraw: \(self.startPile.canWithdraw(amount: amount))" } } /*: @@ -83,10 +86,10 @@ let hundred = MoneyPile(value: 100, quantity: 1, nextPile: fifty) // Build ATM. var atm = ATM(hundred: hundred, fifty: fifty, twenty: twenty, ten: ten) -atm.canWithdraw(310) // Cannot because ATM has only 300 -atm.canWithdraw(100) // Can withdraw - 1x100 -atm.canWithdraw(165) // Cannot withdraw because ATM doesn't has bill with value of 5 -atm.canWithdraw(30) // Can withdraw - 1x20, 2x10 +atm.canWithdraw(amount: 310) // Cannot because ATM has only 300 +atm.canWithdraw(amount: 100) // Can withdraw - 1x100 +atm.canWithdraw(amount: 165) // Cannot withdraw because ATM doesn't has bill with value of 5 +atm.canWithdraw(amount: 30) // Can withdraw - 1x20, 2x10 /*: >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Chain-Of-Responsibility) */ diff --git a/source/behavioral/interpreter.swift b/source/behavioral/interpreter.swift index 20408e1..ee520e8 100644 --- a/source/behavioral/interpreter.swift +++ b/source/behavioral/interpreter.swift @@ -7,87 +7,86 @@ The interpreter pattern is used to evaluate sentences in a language. ### Example */ -protocol IntegerExp { - func evaluate(context: IntegerContext) -> Int - func replace(character: Character, integerExp: IntegerExp) -> IntegerExp - func copy() -> IntegerExp +protocol IntegerExpression { + func evaluate(_ context: IntegerContext) -> Int + func replace(character: Character, integerExpression: IntegerExpression) -> IntegerExpression + func copied() -> IntegerExpression } -class IntegerContext { +final class IntegerContext { private var data: [Character:Int] = [:] - + func lookup(name: Character) -> Int { return self.data[name]! } - - func assign(integerVarExp: IntegerVarExp, value: Int) { - self.data[integerVarExp.name] = value + + func assign(expression: IntegerVariableExpression, value: Int) { + self.data[expression.name] = value } } -class IntegerVarExp: IntegerExp { +final class IntegerVariableExpression: IntegerExpression { let name: Character - + init(name: Character) { self.name = name } - - func evaluate(context: IntegerContext) -> Int { - return context.lookup(self.name) + + func evaluate(_ context: IntegerContext) -> Int { + return context.lookup(name: self.name) } - - func replace(name: Character, integerExp: IntegerExp) -> IntegerExp { + + func replace(character name: Character, integerExpression: IntegerExpression) -> IntegerExpression { if name == self.name { - return integerExp.copy() + return integerExpression.copied() } else { - return IntegerVarExp(name: self.name) + return IntegerVariableExpression(name: self.name) } } - - func copy() -> IntegerExp { - return IntegerVarExp(name: self.name) + + func copied() -> IntegerExpression { + return IntegerVariableExpression(name: self.name) } } -class AddExp: IntegerExp { - private var operand1: IntegerExp - private var operand2: IntegerExp - - init(op1: IntegerExp, op2: IntegerExp) { +final class AddExpression: IntegerExpression { + private var operand1: IntegerExpression + private var operand2: IntegerExpression + + init(op1: IntegerExpression, op2: IntegerExpression) { self.operand1 = op1 self.operand2 = op2 } - - func evaluate(context: IntegerContext) -> Int { + + func evaluate(_ context: IntegerContext) -> Int { return self.operand1.evaluate(context) + self.operand2.evaluate(context) } - - func replace(character: Character, integerExp: IntegerExp) -> IntegerExp { - return AddExp(op1: operand1.replace(character, integerExp: integerExp), - op2: operand2.replace(character, integerExp: integerExp)) + + func replace(character: Character, integerExpression: IntegerExpression) -> IntegerExpression { + return AddExpression(op1: operand1.replace(character: character, integerExpression: integerExpression), + op2: operand2.replace(character: character, integerExpression: integerExpression)) } - - func copy() -> IntegerExp { - return AddExp(op1: self.operand1, op2: self.operand2) + + func copied() -> IntegerExpression { + return AddExpression(op1: self.operand1, op2: self.operand2) } } /*: ### Usage */ -var expression: IntegerExp? -var intContext = IntegerContext() +var context = IntegerContext() -var a = IntegerVarExp(name: "A") -var b = IntegerVarExp(name: "B") -var c = IntegerVarExp(name: "C") +var a = IntegerVariableExpression(name: "A") +var b = IntegerVariableExpression(name: "B") +var c = IntegerVariableExpression(name: "C") -expression = AddExp(op1: a, op2: AddExp(op1: b, op2: c)) // a + (b + c) +var expression = AddExpression(op1: a, op2: AddExpression(op1: b, op2: c)) // a + (b + c) -intContext.assign(a, value: 2) -intContext.assign(b, value: 1) -intContext.assign(c, value: 3) +context.assign(expression: a, value: 2) +context.assign(expression: b, value: 1) +context.assign(expression: c, value: 3) -var result = expression?.evaluate(intContext) +var result = expression.evaluate(context) /*: >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Interpreter) */ diff --git a/source/behavioral/iterator.swift b/source/behavioral/iterator.swift index ca19f9c..d351958 100644 --- a/source/behavioral/iterator.swift +++ b/source/behavioral/iterator.swift @@ -6,22 +6,38 @@ The iterator pattern is used to provide a standard interface for traversing a co ### Example: */ -struct NovellasCollection { - let novellas: [T] +struct Novella { + let name: String } -extension NovellasCollection: SequenceType { - typealias Generator = AnyGenerator - - func generate() -> AnyGenerator { - var i = 0 - return AnyGenerator { i += 1; return i >= self.novellas.count ? nil : self.novellas[i] } +struct Novellas { + let novellas: [Novella] +} + +struct NovellasIterator: IteratorProtocol { + + private var current = 0 + private let novellas: [Novella] + + init(novellas: [Novella]) { + self.novellas = novellas + } + + mutating func next() -> Novella? { + defer { current += 1 } + return novellas.count > current ? novellas[current] : nil + } +} + +extension Novellas: Sequence { + func makeIterator() -> NovellasIterator { + return NovellasIterator(novellas: novellas) } } /*: ### Usage */ -let greatNovellas = NovellasCollection(novellas:["Mist"]) +let greatNovellas = Novellas(novellas: [Novella(name: "The Mist")] ) for novella in greatNovellas { print("I've read: \(novella)") diff --git a/source/behavioral/mediator.swift b/source/behavioral/mediator.swift index b24b844..a97b7a3 100644 --- a/source/behavioral/mediator.swift +++ b/source/behavioral/mediator.swift @@ -6,62 +6,52 @@ The mediator pattern is used to reduce coupling between classes that communicate ### Example */ +struct Programmer { -class Colleague { let name: String - let mediator: Mediator - - init(name: String, mediator: Mediator) { + + init(name: String) { self.name = name - self.mediator = mediator - } - - func send(message: String) { - mediator.send(message, colleague: self) } - + func receive(message: String) { - assert(false, "Method should be overriden") + print("\(name) received: \(message)") } } -protocol Mediator { - func send(message: String, colleague: Colleague) +protocol MessageSending { + func send(message: String) } -class MessageMediator: Mediator { - private var colleagues: [Colleague] = [] - - func addColleague(colleague: Colleague) { - colleagues.append(colleague) - } - - func send(message: String, colleague: Colleague) { - for c in colleagues { - if c !== colleague { //for simplicity we compare object references - c.receive(message) - } - } +final class MessageMediator: MessageSending { + + private var recipients: [Programmer] = [] + + func add(recipient: Programmer) { + recipients.append(recipient) } -} -class ConcreteColleague: Colleague { - override func receive(message: String) { - print("Colleague \(name) received: \(message)") + func send(message: String) { + for recipient in recipients { + recipient.receive(message: message) + } } } - /*: ### Usage */ +func spamMonster(message: String, worker: MessageSending) { + worker.send(message: message) +} let messagesMediator = MessageMediator() -let user0 = ConcreteColleague(name: "0", mediator: messagesMediator) -let user1 = ConcreteColleague(name: "1", mediator: messagesMediator) -messagesMediator.addColleague(user0) -messagesMediator.addColleague(user1) -user0.send("Hello") // user1 receives message +let user0 = Programmer(name: "Linus Torvalds") +let user1 = Programmer(name: "Avadis 'Avie' Tevanian") +messagesMediator.add(recipient: user0) +messagesMediator.add(recipient: user1) + +spamMonster(message: "I'd Like to Add you to My Professional Network", worker: messagesMediator) /*: >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Mediator) */ diff --git a/source/behavioral/memento.swift b/source/behavioral/memento.swift index 6baba83..b38a577 100644 --- a/source/behavioral/memento.swift +++ b/source/behavioral/memento.swift @@ -6,64 +6,78 @@ The memento pattern is used to capture the current state of an object and store ### Example */ -typealias Memento = Dictionary - -let DPMementoKeyChapter = "com.valve.halflife.chapter" -let DPMementoKeyWeapon = "com.valve.halflife.weapon" -let DPMementoGameState = "com.valve.halflife.state" +typealias Memento = NSDictionary /*: Originator */ -class GameState { - var chapter: String = "" - var weapon: String = "" +protocol MementoConvertible { + var memento: Memento { get } + init?(memento: Memento) +} + +struct GameState: MementoConvertible { + + private struct Keys { + static let chapter = "com.valve.halflife.chapter" + static let weapon = "com.valve.halflife.weapon" + } + + var chapter: String + var weapon: String - func toMemento() -> Memento { - return [ DPMementoKeyChapter:chapter, DPMementoKeyWeapon:weapon ] + init(chapter: String, weapon: String) { + self.chapter = chapter + self.weapon = weapon } - func restoreFromMemento(memento: Memento) { - chapter = memento[DPMementoKeyChapter] as? String ?? "n/a" - weapon = memento[DPMementoKeyWeapon] as? String ?? "n/a" + init?(memento: Memento) { + guard let mementoChapter = memento[Keys.chapter] as? String, + let mementoWeapon = memento[Keys.weapon] as? String else { + return nil + } + + chapter = mementoChapter + weapon = mementoWeapon + } + + var memento: Memento { + return [ Keys.chapter: chapter, Keys.weapon: weapon ] } } /*: Caretaker */ enum CheckPoint { - static func saveState(memento: Memento, keyName: String = DPMementoGameState) { - let defaults = NSUserDefaults.standardUserDefaults() - defaults.setObject(memento, forKey: keyName) + static func save(_ state: MementoConvertible, saveName: String) { + let defaults = UserDefaults.standard + defaults.set(state.memento, forKey: saveName) defaults.synchronize() } - static func restorePreviousState(keyName keyName: String = DPMementoGameState) -> Memento { - let defaults = NSUserDefaults.standardUserDefaults() + static func restore(saveName: String) -> Memento? { + let defaults = UserDefaults.standard - return defaults.objectForKey(keyName) as? Memento ?? Memento() + return defaults.object(forKey: saveName) as? Memento } } /*: ### Usage */ -var gameState = GameState() -gameState.restoreFromMemento(CheckPoint.restorePreviousState()) - -gameState.chapter = "Black Mesa Inbound" -gameState.weapon = "Crowbar" -CheckPoint.saveState(gameState.toMemento()) +var gameState = GameState(chapter: "Black Mesa Inbound", weapon: "Crowbar") gameState.chapter = "Anomalous Materials" gameState.weapon = "Glock 17" -gameState.restoreFromMemento(CheckPoint.restorePreviousState()) +CheckPoint.save(gameState, saveName: "gameState1") gameState.chapter = "Unforeseen Consequences" gameState.weapon = "MP5" -CheckPoint.saveState(gameState.toMemento(), keyName: "gameState2") +CheckPoint.save(gameState, saveName: "gameState2") gameState.chapter = "Office Complex" gameState.weapon = "Crossbow" -CheckPoint.saveState(gameState.toMemento()) - -gameState.restoreFromMemento(CheckPoint.restorePreviousState(keyName: "gameState2")) +CheckPoint.save(gameState, saveName: "gameState3") +if let memento = CheckPoint.restore(saveName: "gameState1") { + let finalState = GameState(memento: memento) + dump(finalState) +} diff --git a/source/behavioral/observer.swift b/source/behavioral/observer.swift index 2865485..d54b21a 100644 --- a/source/behavioral/observer.swift +++ b/source/behavioral/observer.swift @@ -2,38 +2,40 @@ 👓 Observer ----------- -The observer pattern is used to allow an object to publish changes to its state. +The observer pattern is used to allow an object to publish changes to its state. Other objects subscribe to be immediately notified of any changes. ### Example */ protocol PropertyObserver : class { - func willChangePropertyName(propertyName:String, newPropertyValue:AnyObject?) - func didChangePropertyName(propertyName:String, oldPropertyValue:AnyObject?) + func willChange(propertyName: String, newPropertyValue: Any?) + func didChange(propertyName: String, oldPropertyValue: Any?) } -class TestChambers { +final class TestChambers { weak var observer:PropertyObserver? + private let testChamberNumberName = "testChamberNumber" + var testChamberNumber: Int = 0 { willSet(newValue) { - observer?.willChangePropertyName("testChamberNumber", newPropertyValue:newValue) + observer?.willChange(propertyName: testChamberNumberName, newPropertyValue: newValue) } didSet { - observer?.didChangePropertyName("testChamberNumber", oldPropertyValue:oldValue) + observer?.didChange(propertyName: testChamberNumberName, oldPropertyValue: oldValue) } } } -class Observer : PropertyObserver { - func willChangePropertyName(propertyName: String, newPropertyValue: AnyObject?) { +final class Observer : PropertyObserver { + func willChange(propertyName: String, newPropertyValue: Any?) { if newPropertyValue as? Int == 1 { print("Okay. Look. We both said a lot of things that you're going to regret.") } } - func didChangePropertyName(propertyName: String, oldPropertyValue: AnyObject?) { + func didChange(propertyName: String, oldPropertyValue: Any?) { if oldPropertyValue as? Int == 0 { print("Sorry about the mess. I've really let the place go since you killed me.") } @@ -45,7 +47,7 @@ class Observer : PropertyObserver { var observerInstance = Observer() var testChambers = TestChambers() testChambers.observer = observerInstance -testChambers.testChamberNumber++ +testChambers.testChamberNumber += 1 /*: >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Observer) */ diff --git a/source/behavioral/state.swift b/source/behavioral/state.swift index c882258..08b4646 100644 --- a/source/behavioral/state.swift +++ b/source/behavioral/state.swift @@ -2,30 +2,30 @@ 🐉 State --------- -The state pattern is used to alter the behaviour of an object as its internal state changes. +The state pattern is used to alter the behaviour of an object as its internal state changes. The pattern allows the class for an object to apparently change at run-time. ### Example */ -class Context { +final class Context { private var state: State = UnauthorizedState() var isAuthorized: Bool { - get { return state.isAuthorized(self) } + get { return state.isAuthorized(context: self) } } var userId: String? { - get { return state.userId(self) } + get { return state.userId(context: self) } } - func changeStateToAuthorized(userId userId: String) { + func changeStateToAuthorized(userId: String) { state = AuthorizedState(userId: userId) } func changeStateToUnauthorized() { state = UnauthorizedState() } - + } protocol State { @@ -51,12 +51,12 @@ class AuthorizedState: State { /*: ### Usage */ -let context = Context() -(context.isAuthorized, context.userId) -context.changeStateToAuthorized(userId: "admin") -(context.isAuthorized, context.userId) // now logged in as "admin" -context.changeStateToUnauthorized() -(context.isAuthorized, context.userId) +let userContext = Context() +(userContext.isAuthorized, userContext.userId) +userContext.changeStateToAuthorized(userId: "admin") +(userContext.isAuthorized, userContext.userId) // now logged in as "admin" +userContext.changeStateToUnauthorized() +(userContext.isAuthorized, userContext.userId) /*: >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-State) */ diff --git a/source/behavioral/strategy.swift b/source/behavioral/strategy.swift index 5a395e8..37480af 100644 --- a/source/behavioral/strategy.swift +++ b/source/behavioral/strategy.swift @@ -7,41 +7,41 @@ The strategy pattern is used to create an interchangeable family of algorithms f ### Example */ protocol PrintStrategy { - func printString(string: String) -> String + func print(_ string: String) -> String } -class Printer { +final class Printer { - let strategy: PrintStrategy - - func printString(string: String) -> String { - return self.strategy.printString(string) + private let strategy: PrintStrategy + + func print(_ string: String) -> String { + return self.strategy.print(string) } - + init(strategy: PrintStrategy) { self.strategy = strategy } } -class UpperCaseStrategy : PrintStrategy { - func printString(string:String) -> String { - return string.uppercaseString +final class UpperCaseStrategy: PrintStrategy { + func print(_ string: String) -> String { + return string.uppercased() } } -class LowerCaseStrategy : PrintStrategy { - func printString(string:String) -> String { - return string.lowercaseString +final class LowerCaseStrategy: PrintStrategy { + func print(_ string:String) -> String { + return string.lowercased() } } /*: ### Usage */ -var lower = Printer(strategy:LowerCaseStrategy()) -lower.printString("O tempora, o mores!") +var lower = Printer(strategy: LowerCaseStrategy()) +lower.print("O tempora, o mores!") -var upper = Printer(strategy:UpperCaseStrategy()) -upper.printString("O tempora, o mores!") +var upper = Printer(strategy: UpperCaseStrategy()) +upper.print("O tempora, o mores!") /*: >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Strategy) */ diff --git a/source/footer.swift b/source/footer.swift index 8e4983a..566efc7 100644 --- a/source/footer.swift +++ b/source/footer.swift @@ -5,6 +5,4 @@ Info 📖 Descriptions from: [Gang of Four Design Patterns Reference Sheet](http://www.blackwasp.co.uk/GangOfFour.aspx) -🚀 How to generate playground (+zip) from source: [GENERATE.md](https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/GENERATE.md) - -*/ \ No newline at end of file +*/ diff --git a/source/header.swift b/source/header.swift index 94ac3dc..9f1daab 100644 --- a/source/header.swift +++ b/source/header.swift @@ -1,14 +1,16 @@ -Design Patterns implemented in Swift 2.2 +Design Patterns implemented in Swift 3.0 ======================================== -A short cheat-sheet with Xcode 7.3 Playground ([Design-Patterns.playground.zip](https://raw.githubusercontent.com/ochococo/Design-Patterns-In-Swift/master/Design-Patterns.playground.zip)). +A short cheat-sheet with Xcode 8.0 Playground ([Design-Patterns.playground.zip](https://raw.githubusercontent.com/ochococo/Design-Patterns-In-Swift/master/Design-Patterns.playground.zip)). 👷 Project maintained by: [@nsmeme](http://twitter.com/nsmeme) (Oktawian Chojnacki) +🚀 How to generate README, Playground and zip from source: [GENERATE.md](https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/GENERATE.md) + ## Table of Contents * [Behavioral](#behavioral) * [Creational](#creational) * [Structural](#structural) -*/ \ No newline at end of file +*/ From 9af97a6641dd4c1a11efe1665c4e6db3c7d3fe76 Mon Sep 17 00:00:00 2001 From: Oktawian Chojnacki Date: Tue, 27 Dec 2016 07:59:45 +0100 Subject: [PATCH 04/66] Swift 3 is here! --- Design-Patterns.playground.zip | Bin 144426 -> 144531 bytes .../Contents.swift | 113 ++-- .../Contents.swift | 42 +- .../timeline.xctimeline | 6 - .../Contents.swift | 106 ++- .../timeline.xctimeline | 6 - PULL_REQUEST_TEMPLATE.md | 5 + README.md | 613 +++++++++--------- source/behavioral/visitor.swift | 21 +- source/creational/abstract_factory.swift | 24 +- source/creational/builder.swift | 2 +- source/creational/factory.swift | 16 +- source/header.swift | 2 +- source/structural/adapter.swift | 4 +- source/structural/composite.swift | 10 +- source/structural/decorator.swift | 6 +- source/structural/facade.swift | 17 +- source/structural/flyweight.swift | 49 +- source/structural/protection_proxy.swift | 20 +- 19 files changed, 518 insertions(+), 544 deletions(-) delete mode 100644 Design-Patterns.playground/Pages/Creational.xcplaygroundpage/timeline.xctimeline delete mode 100644 Design-Patterns.playground/Pages/Structural.xcplaygroundpage/timeline.xctimeline create mode 100644 PULL_REQUEST_TEMPLATE.md diff --git a/Design-Patterns.playground.zip b/Design-Patterns.playground.zip index 2d9df3c1ab71c97a75e088bd1a888a28eef91ece..479877bdaa3f07f280874a636a221cc39a6638e4 100644 GIT binary patch delta 16063 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 v9Pf8#p-7v^|~4j2g-Pg9`>8vYwy`j0kX zRB)OIHjp5#D;PkUhQt7bC;kVi{6A5qVE;f*|4o3ud12te|Hw0^{hB%|E?f|U5MnTk+1=ciT^)W Y|9=bpvwA2!|1}mH&>Yfc>7OP2e}d}2NB{r; delta 16015 zcmZX518`+qw{G^1I_}s;$F^Dac}vCWR1bolz5``*3(tv9RITwe{< zsJUuY%^KerNx#2ToP0r0lmUl;1^Z_~l)EJ$u!H}71&B9^1Ip=<|3ayMRsVNmP67}T zq!KUyi2qedr(F@4{8feheWd?Y*)ssLAc8xGB})+*0et_2N=3E*oT~2#pg^9iaFZHtf%J()1_R>|00WcxH=F@2kP)=VGvSOo;%>7`vv%G8 z9Ug&@epB_U3T;IDquLOw8ZkM8sd@#|JlKmfBf<hh{W1b%si_+-#KdDTmqhFd>lpI1R(=y)mi`aH(n4#tlZY=r!I;d8nNc++(EQSUCeBSfOqwk1#5#AQU*qTN=S(~OAQK~ zI8)lRQXOQgSD~tkzJ9F?yKt@$Q+8_I52276ZrqW4Z8YRz2*XG=W7C}SkT~TY-5@)C zTmZpSPrgEqX~vA@`|;=ayyeNaX?h4PM9u~AnL&-%y~d1wg%Aqf-&qNKsuNk|v7*fC zi>9Ff8(vnyR+9vrlL6`ZLLpbF)QbW}J%N{Q5<4hS3eDSgr8igl;4XM)HT|fZ&uq4@ z@_j|$5T+OSnt;*y#5fb}tH$g$NVzTFbQaXzNi>tb{HEsF9^R z6#T9noi0!!6)2qm8M~\Q^a zV+jzQ*wauCFW}kKQCaLfx6cs77H6GHF#@%p-89m?0_8NzW~*7NR&&VgG?$Qz4*iHN z3>V@hIOGP668&3BS*_CM3AvNvW2WPuYaE<0lP#l!GloRxRrap~G0{|!Eyw-wkg+WS zi^80F3An@hO#_IZ?C33sftSF3xzNE8D?<=6FS+uVre6NH2|$emKJ5d>@9!f2xIyn+bbmZmwo^m0(G_?}%r)9Xc_#y^a8{IWe1(^d~x5sykJ z@Q#hNe-_7X((>y(mCA7HZN`bIR6wSh&Wt(zR3dZ#Ak%pXL(V4s{FCG^Br29to$+y~a1H{Va$G+M z)lkpv*HKGu)W}o@w$gp4&}2B03w>=8*F^LV2vG#D@}#h2*!_AUA*>Xsh{9(-CDV=a zy;~Um`wYtBp-sQAcx@T*0MZ!!iNwyjmq>%AlGp}tq!Et-@w|)2f550pGLV1*7ul*^ z9RF!Rt%h?WmzJMq8Xp%(c>q$GUDQUyFvscpj!PXhYi&&g&FzXEK{b8m71XYwGfR6; z_=1m+feb}zgu(?GDPZj^1kakNdr*P$DIiL$PWbiEW2WbIVt?NREgx7XV+~&+2!B|$ zl(;}A32t_;@r?Ff+X=vq=XOK~FI{yQ2u=o2HcAs#r1CpG42;9wd;`gED%p;H42%K+ zKCRqiDa|+)?p5`ezE5+l{nt(7SiaxzH3kCQ>Sa>c7ElN6tW=SA0w?!(QKq~(ja5y6 zn*#6Ome31=dm%rOjP3I7?`HGDhzZVuVU<%T^AHw@X^w{q0AA|>P$5qNP*Mz{f7V~! zXr{5E3sw8xx-R7%H$fpE@;_>0@P(3%v+vNrethLr*>Q}NtNGw02C$}B3C@Y;ugappL)_ZUnw>$vN=Yr_i`9S4uzzzkD~4@lwc+KG`N7y|7R+ zfFvMhh>f0f@RG58ckAzutjEpx3WDP%wyr99^iv?j7v3sZKm|3Cp9jb0yy3?>68IQD zqa&q2x66=0oIpk}1s7t(0hh+O-v~|&0B$E}O|ljN-)AvqP2?Lj+%u;sRVT&+2^N$OQUY$*k0u7(A)Gq#f2m^|`PGnfhI9Lfe?0kT2;=AK3hau~vPy z+ku$oLhTNHkhEBykF~4t2S?&dj<)8*b4+ZWcv<$WL7-1%!2>fXS@m6dx9_np^DG>G zD4Ft`_Zs5py%tG@CA>4oTT^_YH{Wa^gZ92zetz62oU6r<|FBLGEg@iL@tN-9K*8nV zeW7O7H*fdN2ntjAR7>>*x5LLsSXn&eYIL!rIt3e&UY5Uh0Laoap8k%F!!h-1BGM#g ztt%M?LkG>}UnX=Pxxy%=XQpYUmL9J>S(7@4Ph-Z0)i~sYaIH^@P`S87<>O5f!QNKz zQ=)yWTnpcLH0Z2Xst!ox$mrKO-{MCS zTp=`^O0_sYsL|y&o3Wi{WB#td`ZaUrW->x<-34@YP$iR?p!i)|dj~mv5&C*wV``M@ zcJo?U{oxwJmyoY7y0C9uQ`egIboP1?6E^@;4V&NuJD%zM_Gwt<^BJzANL=8koQ4JU zPW41J6AcMD!!4HHgkhA@1kR=H=&ClDe|mPAs}&M8Tu==mI{!>NZ)X}#(fk);satpE zFD?-Dxu8#fK$1tu+7XG)uidXi$%cyev*@nK3v06X5fOdxQ({oJs%3AHc4T1}`-3c{ zB=6z_toN4i-Ik&?WNhyp_>Esm^-C|-NP;s&e|%bBoKoOjSs==>cI0o6l6q8jHTO!j zIu?+^MONy08x+UGwjm?sOB|*?gwqpJ*m{Dfh+xes0~M1kJhvbawSIU)^1w&(FK=lz z1yAY8=3(?qYnvDd>YqNO@`Xs8N`}FTq>6~+YqkLPwT>{N3uqxKu02t^^$XF;kM9-d zFA`XZg7S%ram^%ZR1QU625T9`0?7iLNNE5TEoN5o}2ldYve_ThIo2IgR^-r0A8b@g6y&;UkdIqB1a%E4&j{nF|6? zf~=*9H@YwKOjQ7Ul?(B+6#-e0tAUt`m}wHEZ2GlEU_lkAspjzFZCv;@htjQqQS@mS zfBaU{elo6z`yw>`^xBw}y8H2r}!l8_B~*f5LLD{bl@T*Z5Ejq@Es4BSHbJFLp8#lySZK&k7wZYCxuIwWYBl8 z0Z3(o4kiW?Mp)TFqUB3N>#XZS*7L$8*9+X&u_*nASQ3%Xppi&cbl<)%Br zYv-W$so55k^|FFOS$_=<>RVMiT8hy2={d9v{EfuQ*aScH-CeAmR*e`0dXzZl(~1!@ zNHr!^Q?aT;m`Tyvkq2|fLwr(w5*=RC!iD33vgENTq-k@48-;}uKL9KE4j zv}@%@aFp$s_pTZ8X?bvENk#_bga;G0H7r-DO&zSsO|M0u`BCqxap#feNrHM~jbuij zw;v+DdC*pjBFpGR6t3%EAC+v~q1jPA`O%ZyXXpYSczDJ4!%rr?MkNXFmUp{(ZR}Ju zk*6u>&2t{En=v1={!B0kXzg1J!Qk{5d;};lW4Ri4+wT_ua=Do`jXyZ^sCYK@#ddS# zSK)GSW!c?9EdBO3%8zAlZ6x^3jfpS@`w>z~$Lwz=2Ab?csOK=R>Al$jX)R!J+;Ijr z&IWo(T~wanbY?JaHs&@gm_lX`8*=g;akZFO4I9P8hfR)rn>umpnQ%_VnV-}Rug7mj z!QM`oi==)7;u%Ca4yuA01Fk1K^1kRU5cJ`hl?)v7Pniq7pm}CoEQWu3D>TWI=GV? zcy**eyyyJz3^~o{inT}9b$O`)Sk>^coKwxmgySEjkvr|^h|?Dz;8j4AD7_y0nn~IF z6L|sh;}C|5Qah6Dj_*My=U&9dRAhc+T~W|$ z{XUwfdh%RB*<4iZY-gElXiAu!DDqzONXkdV%yXV|M8&Eq^&ZXu((Uq#Ph?Uqp^KvVA3z0j{KvtB2O%~X_lEtu{57#a9?vAmfjhulEpcg!k`xMryx|g@tT()??}NL7tQu2c2J=5+)D55-l4` z+RC-=cxOb%yqNqAr$VSRsSm~8e-+?@^l46h-e+5eA&&qQRO+fF#GB^XbA@`gkL+HI zEQ#4#*#^HevV{SNSkw{*h&KCjC ztrelLj@DJldcR-G5{CAM&2p}pAv$x%Zc3Vgt~X<__gj>ky+Xjp2XyLWAYk-=YCD4T zK)h6iH~{Rw1)fYOvTU?3e~U#}|54z9O8wVJFc|O^v>CfTjNW~$B73MGAH}v<H@-cxP3g=Cvps)x}-@UZf+iq-u34DZn0n){HbSmWL#r<+QibE^jY-b`d z)YzN+^O@-PSdlivAxFj>LhGij9oy> z6x{6*r1fIDiu$O_T)6ZYYGX*mAq=!6<|wViIaoFv6t9offz!qjZ=7fAIK;qAcoAQr zQ~BwTUoZ8=CV$PDO4dd`eUWFOxAJ!VYd8XGqSKNyl@QB3+=K?g*Yr&wOaG(1>X`oS zek86^UDF($${Dy_%4ueX6{DYtlr^h5P4Ws3sDyRj4S@}%Sr5FW|FVEUK|6MU$8E9f z2=RTAV~XK`S%pZ zpQSZ>rraRfC-$RzR>H{_mD|C=c`WSYcyQ)%=i%Y7LK7I!qJH;B%<$V`n?P&?Oq8eVfeG8C#oN2Sr` z1T01`sqL98JYL5ek>(mIlgob2>TER3R2vyg4TdcMooRt(PU2cP$SIA7Oc zvMen0%S3&uww7A?@Goghf)#Srf}x^r&;*wMQdcDwcjVX$se|_@+~YHhPCKLoW3B}F zMqwS+uknVaH@btIR61as2@-Yvla{#$esl0nXxGU)`pH-KN9>6>Mnha^Zi>+q43kq7 zOJ7qHO6^)5wM<%;>WNjj)+QM^y&XN-tn?=zmY9%)K=AS!2) zBD~p#C;7>dPZvlF;^0Y(cs2fzy)~Xp3wfD@7(8tDA6lB+6fKq zd0y)tl(N740DOO5Y#9hzE{w?!{=e^*xT5>_L*mY23OYTYWVF|r3FFQT|zR${WwzP*f#}p%vcF-<{9Se z;|2wDu^*4)U4awBOx=D0rddC zY+Hx=^1UG-Ev&3OT3tD4L2XUDSzkyPaLl~r#%4;_bPW`nBa|eKTrkgj>(V4C#V?pj zCJ@Hv6P+-D;m{ksj(e!_AO~c-ESh z1C74GA6`(c#}Igwp4;Dha@;P(z_`|vJ+2R!p)~O5QaE{tSg=^agJg?_O%z$7QHjj3 zgiMOXBp{o@OM6}AXR_`lLvVlc_ULtvIl#g1X8LLvZfqTRh%xziHVdx9XnYG3OV3ao zr7g}C4qxb@5?Iw)Z);L`TDsg=b13JQRLPb$DWWBxTi^W#-oI|qHQYT{=MfFwo=PCu z6D_D6oN&riBlN4I57d07K|US&M+ZJVl!xDgEY8FW!ZU3CI1D6)HsOB-HcOoL&~O5P z_?d6x2{|BnZI{QYuR;QR6eRd^q5fTUz|RESQ{{#OvGA>kMA(Cp82ueF83;-Gf^P4v zraQ;@s>qm`cP3WDHfr4xrsr`X%?4e&c%fFY1>Kk?d37?c529J#Atbq$-28ZD_>4A_ z`n=Nc3V!;%xGW+C?NjYYAsF*u+NWDVA)A|PwNV3Vw$hlGNU%ce(cK{*r#RRJ>tE3f z=E29jP1f`C8t?uEh7MoZ7vOizEH0o{q{w|TM)TSAWoCMd^2C-G2OO;8@jNOQ%(T<0 zxFzaBBqL#46@=jBB-*<&|GJ8l$dRBnkg?DArvEX(l!4-LwU9&&bqJh~1h;w=MnKprA6=5d_i7H4c*kvoBt05p|Uv4)-AW zx%Yj?FruuJj8T!e%h?{&A1L z(WCC-Ff_Af7v}(qKBSM7ls&6MnG`nWslFlDd+7_q{^^&BnADM9lR`*qWM5+qOgMKf zAlt5vmq8*>F)yc-=^R8>Gz9hys_2%B;Cto z?XHSf864IPFERk-d?NJsWXCnm*Q~8_4N} zTP4Ys@HlCU6L|e$Ux4=KgiVYK^4XGw&X~h%J#J0?k|+Khv&AeLkp5pR(qHmO^WSTQ z$^NfGN;ojE5sLqJtpG9p!y9Q&C2lk$ci&MFof=Mi4{33^a}g|-SvUQpD=+A|9X%V6 zKJ1U*L98be1mB4kkFD6drBaiZ=O-)0^Bdzii08OLJwTpAxX#VmTwF8LI3h|AEClhp zaY1WzBE*LI2(rzEzAWiI~nGzL>{^>!q?UI;HgOqmp&aQH3Z%MOJ;{jBauB=hvL3QM) z70~COfu{q;5-!@?%LRcM9~dZQ4*gYyR*DdFChZiOHmIL{YspbjYj_O_qCj@*0RS02 zNqV1gHw5P-y9G|)8fC_DIGXVZ5BB6YTzmCidg*fdfF-e55VeiWC}dguuP*^_?K`jw zVEUY>#dwPFd{>Vb>j%5IkvoMCc?AgxvSW9w=BHS?7EO$*bdg!*-)h57<1NaDIS2x_ zGpL1!yvF~Y_UfKi0$ty=!*sgWa<)Hfn!iQB#<~k-eHS0vC0>+kaS7!Exms;yaz=lW z2@N`kCM5qiC>n192zEA|%WUSkkkK@+>xg>4%=5P*%+0|~b-1U{zzX9NHP%@({l#mj zfuwqi&WaFeu@Ai2n1ih0>_WBrIRnSMj%jf`Tes`ulD$JCvjl4}w(N;5oKC$V(P#NY z%F1k;#(uOJ&_1wYf387(Xj|$ObU}NQmP*6J6S#W=3Mn~e=hWVr@(AL%rgMJUzs|eT zKDdXuKXqR+QC)3AJ0WlRa z;ZAR0Etz&4uO4akCBo7hz+beY!`(#YA^q8yK3Cj-^(jn1NdPYVF5B8TU=pF&kVWk( zAuHwzg7KH{o6#C)mXyvIEtRjw54k>QVtK#a}mJogV^}F zyQDpynVh)8x2)WYJC0ujs*hxMz0JDX@2S$|>i6a#m33?as!^th zck*WI8QVsY7tt62w=1jmc3734lYIQ#OIfKS&nZLXEKc7!Yc7->nLC>4%sie+C(Sok zzc4o6Z4I9uS}~@3c0n3lfc?+|7Olr(FPm>`g(Oz*EK1VvKW-mN=G|UnIgJ^BA8PvN`L0p9zucki*!dx(jkONevES z(hr3n{c)|pnfH)jiP%-P;AKngTmWk}yFvAi8`_aKa=u3^r&*L z3+`krJcOaUL_G_%8zKTqG1vl)dFATPMg zUOR2ZRfZN^ljeN4y|)>ya}DH|Wy1W?@Vq(}Wv>CSn4fKRU}g^RL5=}Z8O9ue2_aZ* z^6{B;p*rYMie7>log(lvnmwzdwnY(%OZZbUre|Qp06#(Z)h#fA#G>;UJHtv>05pR+ zB+MzX4n5IxTU|L0)FuEv-~M$4WK0%)R>qeo)z6KHBypaw0OkCa{dz%>m*E?IC=)#u z>&`k&lcA}-a@)(4qo>eYtJ{T3&`2{&6O6R{Dqk(|#g#|bM@XT^UCH1QCaU8H{E27P zTtB*z+z&91ho^`u*)m*l++3bkq=H5XXgnWM6G}Ypq6=|g02OOW~FoP;2^~VI;#y1&$lN@nV-aJ5@wYo z8CGAz{TVmXLl2gJ&)Xocg{4U@3T6t`Fo=AH9^H)26%ZPt%iB-Tw z?n--r&a0-(dw`u1zIM?O_LQbu?1r^O0Z%4vOb(xpZ~jg7cvnAxD+s#3BF6y#BWkof`ct=1Ic^b3DN-F3S^*?>MTYbyQMB{g1!OD26e zg%)zvHRwdLk&eR-)#Pf9iPsYrriRveK*)wOB!02^OA|r`+)`3S9FHpcf`-x!2M>&nX;*T~f z$9@dbRFfQ0|#R`T@kVG2|JZ-J$JrW24BQdOdvUUZ!Y zvqAo~Y;3tY`yli;V4x`kcDb>6fEVo~C-plzwlHstq{eFh=G83RBVHS1OGoPk>RASh zu#N8;pD0)85;an!JAhS*9yu`fbVLuVX1P;#FLp4pKcm0erbzl5KGgM86xJBrdIMB@#Nuy7wrW zFjHoYHy=xTKEXzUSts>-clI;wp5~g=UJp5a{ydrJQIgLvQSCe+`Ty3GdV|-bIPmKX z4lGov3kFe{D{xXv0@{>{A7#Qw;Ubom$0Hz}3^9uku?9t!{*t23q%O3@-iUV6KXqK( z(C}6`OM^7m4z{KD-)Yh$!W8&08&vSr12XJmSiH>jF!^`odvA=O>2;Xpn z(rnF;QR2f}K5Ovqq&S^-VLe4|{7s`!N`~3&jzPc6in7#(H?0qqv<0<@uX*x}41|Yn zfugoV7EoNguC_izW_s!Cu=%|bvO_CKV&?FarKmzQo+;Q;*3^fpoIe9`ML?=>cO~;%?uuJ~BowI}W!CN>Hhm z1wh_-Lj8HTlPFfm=B=cqg;SQ=4^3V{s=-!GNj*rEKvKYj(*6 z;AlOlR^YXxvHR!hFb8~n$37Rgx1?bf=KmS8lN;1gseDujl=ai~IP7q%%avS_CNc~_0GNf_`0km7P zG66{B5P4n0lBqSl09)jLkcoehZW}rn7y>UCnB%_Sk?mV-)| z(yW{ajk5TQT~a1KS_cUwT@zh#C6k@K44IsCqB5*HVpQN+tHZvq4g@lC?ml}{>?9+&B>=6p7^=%K2m zWv~DtoD)GLs7HxMb3f2DH5Cq=c>e=eLa0m8u&1q2tiW0;?{~xP&cFi*W#JNlqjB!W=CTEd*b<6WXo zScg8JYbswTgMN)`x;OCd0i(2t0VjyqL8Y{iZ+n(_LEm;gv!cB;zlWR*{pJK$=p(5d z#;F|oqZtNQOMtmY!V9fo_(g{?8rgP;vw9d&H^}Bjw-bzGpWKsNKSX2y!4q{Wx@CvG z6TxH8z7y_h2>Kdi$Vkx`!P?JJk$36eeywv zXou#JyY|E;!OxjQuF^_hA+mOorBjFGagrE2I%UqBG*5`=kPUoB6mcPptS^N|@L8hX z%<%~j%n9kBIgeh>(a;;+K-$p&Db{fLJYro8(rihBaUBX5q)_mLM=d2#)Ime^G3JpN zxUwoNnMKtDN3wYTjU^e{9{*XxB zr}TH8S;g$BGt5;2;BGJc1a|{{DRy&NUN3fV^XXPlEL?Mh&&D7o|w24or!{k63&8o${K>^wJf6qx|2BP;ER$P+7pzepyb0 z$UH2NbY3zoYcjJXmf4&mju5HUf;{Ch1~03IheMW1e29<6=xENf_qB67=;ZH9;! z|3vtnW^_=b03HJp#D0RMZFLXn9LAFtt#2{g1nEV}hgzSx0HM|-!?oDV1BWDWF8ODf zc_txJXy8rkUfDs-?sxPWIOz-O4l)`q+wZ#|WzA%%IzyM|FLWpM+ zfA%L*Z);9*4shuVZ?(ji2Mg_DZko#kRBPMo*bc5NW5w6{1Jpqc$-jQ1XhOB=)h5fI z0tsVM+?X3HtJ%43vRW5VRP0v1$ZdWFix{3I%g8dU#Zwm)=YZJ78!x%p{2GXnA&5!^ zvY@h<-@c=L>zJ(T-^N26UI!{K4i?BY2>F-uBZoDUr?8m`U1lfL3XEqHA?6ISUeucR zvL4@BIa65}E0J{&q6R)pP}@+i?fGA(L^3>F+iYYm?8elNSz!MlJISmJLwd-(1h#&4 z?l5Ap%}=tj=CBQjvZ9t#Sx_MjX;qO11r+i5{WyOamK3Dkq2Oe}Vvs~cBZH4ueL8f+ zKd=v@*^zFAtq!%>(H<`aQj^iFN^T%7yI6E3d~QH+BxQG$r+!Z6sT_EjT~ixuo+3dP zeK$^7D_ekLUQ{Msb^-osl^86xWZcjt__2(os7FVo3LA$~PKA<^=ut*HGFq(;(pEx! z8d*06ZyU2;#=ZB|CZG~AJ=IScefsvJ9p64IntnwnmVQM_9=pVBjvG`a7l}Udl5`o$ zSC6_SR!!fUxp8Y9RwfibqnD{b7^?;Yv-i5&N46bi$$dx$MG(*x-{JPN;AfK!*N3JV zB}(>|)ha<)RRfEV2N;0@vuB_@=)&Zhl{X1(Un@h(D|C zOA>01usrQ{A&(0}j_;bi6Z}dUCS|s=yVr}5U-sr?e#ZpSu()2L1%rwpJMRtegD0dO z?L)Y*Ot++S?+|Ugr=No=8MM!G7bT6 z%oX^SWiU@*8;OKRc_Nb1PmM@Z*Kg9Bbv65?&7&9Tn)EIBdpP{OVwgAUFKkzesbbiQ zA}>`j3njM24M5VbVDs4HL&ex2r!U%$lt@w988gUyQ9T^<4!5cel2a# zKJ1-;>AtQg!W-Az{vMfz4&wFn+t?fcfLLoAF)bH~FJ;`Uoy+}etZXcI7ouJ^EwP8M zD3dbY?D9PY9#^|kD-PC8oT`_s%h{-ho}qi-xtXx7e8}bcFAC!8KkwlX@uK!sTjX`q zzH@ENJCZEA?UHE|G591>%U>P2HDaT}m+Yvf_l>D;hs;|NA1YjWwuw2M3& zMPP7vQ!L;(lYY$Z1S<}4hJCZp3@p|RJ>-N_7+F0iY#38OSdauHy6<3nQcMrQe&mFy zEr?E`l`g(@1+Xh`fl$11Y41kfoA9gV_Vjhe=WdHiG|SQ7U<)3WF*)KRGkitGC#1=L zPDqQ6ArFgx8y?qid6>|jZvm&5kDjW@nV`ZYrGxxfT8dZw8jgv_B=5+?E;#J28z|$1 z{c>%4Kkp1X$JH1pyikvi%hYR92$Si=6;hruGAJFX9PNzp1LWM3g$@JR`XQkv7DVS8 zBr~axYn$NNKR?&*>dr`n9wzK!T*tnu$OZnzN2uGiP2lvHB1-*rU@Ed12e(+07UhBx zF^sgL00RR2=5PZJ+EEgVCuK;eyFLYLXhk?@V`T4kNf>!sabUOU$o9i}l3(p3DZAA7 z>{C0_nSA^=1!$D=%H2&qErA(rU&MI3c-m@YaQq_Y2VFb<8e@acc~++7q9iM>LFrT> z0!xj=LTvifrIVvQPI~W=tIKMqeoSkdseOSSse8e|>4JTEfsAS}Dx2}KlQmVAMsk() zG9`vBL5+L;Dn32#@zGLv=KPq5jH}fFseI;qb+)5?DQIG-EdmGTxSorxF-RuaNwm=l z%1J-Yy}#{3`ot#0*}mo}O;P?2t5{e3MlP?q1M}!1ZY9fPwlq_uU27yJ_n2{`_$r*w z^Pzk3pM3vZ&Ccccj)Td9Zx~cO$y4@j?(($U%M}OjZr15{-0pi`zB+ng!Dmk3_JeYs z-MUUs_Mkx*(wK4nu1W^n1RW??F*t?ym(<@{E}l-U-ufzgTis0Daq6?))`jx9#f)0l zC8k2u9f77gq*|X9UYi(SJ8pzK!`H0nW-hLkJEIM%dM9oo#r*CjHOO`%bfBw#YglTf zRW#XLYd48r$gHc%QMIW337WO1#fJ>gu3ZjIYM>c=9Q$Yw-NK-}LOLOd>@n z_t*;P@cq#l0L7T&ELK3V10x0da?0YBU$aM0ebG?|ebqOXxufq3@7%Im*oySD4_Fh%oD*}sVfV$$?frH`)gD}3^z%2)_|IG#HY)VB{!_y{ z=O%R(8_XssJbI0o2x@vQNQx3K0Mht;XE=yqcj6gVPdath;pEniF~Vp2EPjCHiMBmZ zqoFeyS8oLFn^pi*dXjGVaK-zD_41$v7n55fM_;v7bfYtNy$Te1pk#7tQQfd*t(v|4 zZN}5_#$lkO+Ik0({RK_i)(Fx8^^L&q3VO=p+p($|W&LJx;jVWQuU!n;cu?qP$_WUx zW7OW<@)-aMD6xM7_7t6+gqmJ~_YC(uT&Xy|euj+)Pz}YMZ^=hP&Ujw#Hog2Wh3pC=fC8xLiw>Fmw3# z^C}w5n6RLQOYgR;3w+`mY*21b%Jd@+`JmLgH)84I?V|f#S@6%>uZgU`UVwOQxig8c zcx@>*rFfEKj8iLaNDyBu(^7t2G`fJD|D@dZiI`IAeUAM^!1`I6S#PR7fO!$>eIDT5 z9wpNrCWu~?vk#m&=2li9UO{PIut@h^;PLV?n*1@(cMsxePrY0po;IS<3=bNAzh~qt2pp$u63L2e$73<6&+zG~ zIOb*^zGts~VUsd$AW=%;Z3yno zPaE{EP2UuMwG`O)MpR5DNSampJyDzO%rWe`vz>=K5XEAb#-+>ahgpTQ*if)&v|PL7 zu5-B7UoxxgrAC3-hzN?IChX8~wbJ;-U1{GYV>Dl}_NXmJ2d7;_o29P5SMSs145vur zuHO-gK+v*C2X{O>D#PpEBEz%m8AvY?tX4Q3I6}9shQ@YlRAaf!NYY8)5vpn2u!e`j zK4PmL*FXI;0cl-yT4`W0vS6Yrzi_41j1Q-|(bhdoX5w&d(;Y<6s9zOrbF4)38mayb zfSCH@-6?aRuy%g36|rWK{2M?UpPrMiAT-UwMN99|gzJUVIBNE&zU>^`Ct7;{dO;+= zTxQ9;3YMQ|BX&B(_Z#wsvj|xNrn8G|09?J7NN2{c5dD`um0y`=kYXItfw)U zLjQvvq5hL=OIJ|V-u>Fa0CtS<6sb2GgjuSL{B>iXX^qZ=3#n2BQIh-hvzhxpdyf;($Ijpl^f&+P>?I`mdwzt3wzlp0uj4Fe7Sj02d96>m z-TFojbs~2uNpQkniQp)DRUP|XIT5x81$K?za6qQs=H@}kAX}Vi@p@YIL5y0ks5zm(9+ma-CruroxCGMZ=%|Qqds$m&X#6-Rhl9rqm%KKDKk3}*(jgma*>Pvy^;0PJX}B;rj&CQ~eC1XB2YcrU0H zqmo_M0cDZi+PT{C+O^u@+UeS@+F8f$U8n)lPz!hmtSweN=1!C6q+P!O=uifD1MF^g zkgv&e$F9zRM<`)*x_DgOs%O9r&OYLP*D!Q65;h?dzx9R#uchzIbHEMhe(CT`OjwKn z7KrtO3?3!)i%5v9Q81%)8rcDCQV5lBf+Ddh%woTb;>tHX&{qP?9JCw^ebg9=wr6q#dYw`nDr@=Q}K_>5haFTd{VeyhwMmkg8$WOg(9 znZ2yt$NauJ5<2QLkK!80vLY}dFyo))9p+uivdb}a&!Cx_I%2;gKRTQ2m}1Bj05OA% zKDOS1{*1Uv3J`B5<|Od*`k8vGdpmiXy=eXZtem?9RaEbR#SW;!U2#e1ZMk&k-f<~J zZ-$%Py-o$gC7RZ6;1q^`xr?Bc;9rtXz-kENArX(|vYxEc)cT!eWo`D;KM&bt5?i&A z3OnCL6uZ#Id>E-pO6M$ftEclL0_1_9CASpsW=iUn$Qmy`Cz>IZ(HO5jC%!f|Vj3cOXJQv=ZLN|rRB!GJN4-r@Ig+vXK-iaAMn{I&(aSgNN?C*2l$7!Y>@BN_6rFJtE>kJOXx1coB$_YTxxKtHc07z!Sl5z_|1 zLzq~#UwZ}Op%%Nj-`(=NILI>4d~b3EoAx+J?9=?N~8(W+caK!h4Gn#<9dz9F@G-FnX#*br`v)~ zvXR5!$PbB(t!bYT3VxQ@pmO}SQ`89(J^w*B}fsfzD_SK}ZZGYrB9Zwn? zF5NZuq&J;CS~^BjI(+n+emXT>{w?BEdAQjZuAer)j;21Vb%VwouGilXKa)XgSN90r zvn|i++eho~`rErtf8;;guMh=bd~;?n_fT5>3XOMrhB9@IeVf58DYF!*0!Lj#ok z7vRwWaZ?v*fO3fcdsH};kro&MvQ37O?L>CEfHuQ6Nst zf7tw$;H3WRufXuvf9XGUISfFq|H(Bm_P^ZzHnEVT{&$-HtI6fxB>!KU7yo0g4fN0W z59j|rh*T~nAOVm!Gu4S1D3E%Q2|!D&WCBtG%l}7$l4`&TBubTF{wrRq`p3{0AerjO z3{?47f%re4`(F;gfdz;Il_5c6? diff --git a/Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift b/Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift index 0250790..d91a3c7 100644 --- a/Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift +++ b/Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift @@ -19,18 +19,18 @@ The chain of responsibility pattern is used to process varied requests, each of ### Example: */ -class MoneyPile { +final class MoneyPile { let value: Int var quantity: Int var nextPile: MoneyPile? - + init(value: Int, quantity: Int, nextPile: MoneyPile?) { self.value = value self.quantity = quantity self.nextPile = nextPile } - + func canWithdraw(amount: Int) -> Bool { var amount = amount @@ -38,7 +38,7 @@ class MoneyPile { func canTakeSomeBill(want: Int) -> Bool { return (want / self.value) > 0 } - + var quantity = self.quantity while canTakeSomeBill(want: amount) { @@ -63,19 +63,19 @@ class MoneyPile { } } -class ATM { +final class ATM { private var hundred: MoneyPile private var fifty: MoneyPile private var twenty: MoneyPile private var ten: MoneyPile - + private var startPile: MoneyPile { return self.hundred } - - init(hundred: MoneyPile, - fifty: MoneyPile, - twenty: MoneyPile, + + init(hundred: MoneyPile, + fifty: MoneyPile, + twenty: MoneyPile, ten: MoneyPile) { self.hundred = hundred @@ -83,7 +83,7 @@ class ATM { self.twenty = twenty self.ten = ten } - + func canWithdraw(amount: Int) -> String { return "Can withdraw: \(self.startPile.canWithdraw(amount: amount))" } @@ -184,11 +184,11 @@ protocol IntegerExpression { final class IntegerContext { private var data: [Character:Int] = [:] - + func lookup(name: Character) -> Int { return self.data[name]! } - + func assign(expression: IntegerVariableExpression, value: Int) { self.data[expression.name] = value } @@ -196,15 +196,15 @@ final class IntegerContext { final class IntegerVariableExpression: IntegerExpression { let name: Character - + init(name: Character) { self.name = name } - + func evaluate(_ context: IntegerContext) -> Int { return context.lookup(name: self.name) } - + func replace(character name: Character, integerExpression: IntegerExpression) -> IntegerExpression { if name == self.name { return integerExpression.copied() @@ -212,7 +212,7 @@ final class IntegerVariableExpression: IntegerExpression { return IntegerVariableExpression(name: self.name) } } - + func copied() -> IntegerExpression { return IntegerVariableExpression(name: self.name) } @@ -221,21 +221,21 @@ final class IntegerVariableExpression: IntegerExpression { final class AddExpression: IntegerExpression { private var operand1: IntegerExpression private var operand2: IntegerExpression - + init(op1: IntegerExpression, op2: IntegerExpression) { self.operand1 = op1 self.operand2 = op2 } - + func evaluate(_ context: IntegerContext) -> Int { return self.operand1.evaluate(context) + self.operand2.evaluate(context) } - + func replace(character: Character, integerExpression: IntegerExpression) -> IntegerExpression { return AddExpression(op1: operand1.replace(character: character, integerExpression: integerExpression), op2: operand2.replace(character: character, integerExpression: integerExpression)) } - + func copied() -> IntegerExpression { return AddExpression(op1: self.operand1, op2: self.operand2) } @@ -311,15 +311,14 @@ The mediator pattern is used to reduce coupling between classes that communicate ### Example */ - struct Programmer { let name: String - + init(name: String) { self.name = name } - + func receive(message: String) { print("\(name) received: \(message)") } @@ -332,22 +331,20 @@ protocol MessageSending { final class MessageMediator: MessageSending { private var recipients: [Programmer] = [] - + func add(recipient: Programmer) { recipients.append(recipient) } - + func send(message: String) { for recipient in recipients { recipient.receive(message: message) } } } - /*: ### Usage */ - func spamMonster(message: String, worker: MessageSending) { worker.send(message: message) } @@ -375,7 +372,6 @@ typealias Memento = NSDictionary /*: Originator */ - protocol MementoConvertible { var memento: Memento { get } init?(memento: Memento) @@ -410,8 +406,6 @@ struct GameState: MementoConvertible { return [ Keys.chapter: chapter, Keys.weapon: weapon ] } } - - /*: Caretaker */ @@ -449,12 +443,11 @@ if let memento = CheckPoint.restore(saveName: "gameState1") { let finalState = GameState(memento: memento) dump(finalState) } - /*: 👓 Observer ----------- -The observer pattern is used to allow an object to publish changes to its state. +The observer pattern is used to allow an object to publish changes to its state. Other objects subscribe to be immediately notified of any changes. ### Example @@ -464,7 +457,7 @@ protocol PropertyObserver : class { func didChange(propertyName: String, oldPropertyValue: Any?) } -class TestChambers { +final class TestChambers { weak var observer:PropertyObserver? @@ -480,7 +473,7 @@ class TestChambers { } } -class Observer : PropertyObserver { +final class Observer : PropertyObserver { func willChange(propertyName: String, newPropertyValue: Any?) { if newPropertyValue as? Int == 1 { print("Okay. Look. We both said a lot of things that you're going to regret.") @@ -507,7 +500,7 @@ testChambers.testChamberNumber += 1 🐉 State --------- -The state pattern is used to alter the behaviour of an object as its internal state changes. +The state pattern is used to alter the behaviour of an object as its internal state changes. The pattern allows the class for an object to apparently change at run-time. ### Example @@ -530,7 +523,7 @@ final class Context { func changeStateToUnauthorized() { state = UnauthorizedState() } - + } protocol State { @@ -580,11 +573,11 @@ protocol PrintStrategy { final class Printer { private let strategy: PrintStrategy - + func print(_ string: String) -> String { return self.strategy.print(string) } - + init(strategy: PrintStrategy) { self.strategy = strategy } @@ -621,41 +614,51 @@ The visitor pattern is used to separate a relatively complex set of structured d ### Example */ protocol PlanetVisitor { - func visit(_ planet: PlanetAlderaan) - func visit(_ planet: PlanetCoruscant) - func visit(_ planet: PlanetTatooine) + func visit(planet: PlanetAlderaan) + func visit(planet: PlanetCoruscant) + func visit(planet: PlanetTatooine) + func visit(planet: PlanetJedah) } protocol Planet { - func accept(_ visitor: PlanetVisitor) + func accept(visitor: PlanetVisitor) } -final class PlanetAlderaan: Planet { - func accept(_ visitor: PlanetVisitor) { visitor.visit(self) } +class PlanetJedah: Planet { + func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) } } -final class PlanetCoruscant: Planet { - func accept(_ visitor: PlanetVisitor) { visitor.visit(self) } + +class PlanetAlderaan: Planet { + func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) } } -final class PlanetTatooine: Planet { - func accept(_ visitor: PlanetVisitor) { visitor.visit(self) } + +class PlanetCoruscant: Planet { + func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) } } -final class NameVisitor: PlanetVisitor { +class PlanetTatooine: Planet { + func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) } +} + + +class NameVisitor: PlanetVisitor { var name = "" - func visit(_ planet: PlanetAlderaan) { name = "Alderaan" } - func visit(_ planet: PlanetCoruscant) { name = "Coruscant" } - func visit(_ planet: PlanetTatooine) { name = "Tatooine" } + func visit(planet: PlanetAlderaan) { name = "Alderaan" } + func visit(planet: PlanetCoruscant) { name = "Coruscant" } + func visit(planet: PlanetTatooine) { name = "Tatooine" } + func visit(planet: PlanetJedah) { name = "Jedah" } } + /*: ### Usage */ -let planets: [Planet] = [PlanetAlderaan(), PlanetCoruscant(), PlanetTatooine()] +let planets: [Planet] = [PlanetAlderaan(), PlanetCoruscant(), PlanetTatooine(), PlanetJedah()] let names = planets.map { (planet: Planet) -> String in let visitor = NameVisitor() - planet.accept(visitor) + planet.accept(visitor: visitor) return visitor.name } diff --git a/Design-Patterns.playground/Pages/Creational.xcplaygroundpage/Contents.swift b/Design-Patterns.playground/Pages/Creational.xcplaygroundpage/Contents.swift index 45c1e1d..bbdd2ed 100644 --- a/Design-Patterns.playground/Pages/Creational.xcplaygroundpage/Contents.swift +++ b/Design-Patterns.playground/Pages/Creational.xcplaygroundpage/Contents.swift @@ -33,24 +33,24 @@ typealias NumberFactory = (String) -> Decimal // Number implementations with factory methods -struct NextStepNumber : Decimal { - private var nextStepNumber : NSNumber +struct NextStepNumber: Decimal { + private var nextStepNumber: NSNumber func stringValue() -> String { return nextStepNumber.stringValue } // factory - static func make(string : String) -> Decimal { - return NextStepNumber(nextStepNumber:NSNumber(longLong:(string as NSString).longLongValue)) + static func make(string: String) -> Decimal { + return NextStepNumber(nextStepNumber: NSNumber(value: (string as NSString).longLongValue)) } } struct SwiftNumber : Decimal { - private var swiftInt : Int + private var swiftInt: Int func stringValue() -> String { return "\(swiftInt)" } // factory - static func make(string : String) -> Decimal { + static func make(string: String) -> Decimal { return SwiftNumber(swiftInt:(string as NSString).integerValue) } } @@ -58,15 +58,15 @@ struct SwiftNumber : Decimal { Abstract factory */ enum NumberType { - case NextStep, Swift + case nextStep, swift } enum NumberHelper { - static func factoryFor(type : NumberType) -> NumberFactory { + static func factory(for type: NumberType) -> NumberFactory { switch type { - case .NextStep: + case .nextStep: return NextStepNumber.make - case .Swift: + case .swift: return SwiftNumber.make } } @@ -74,11 +74,11 @@ enum NumberHelper { /*: ### Usage */ -let factoryOne = NumberHelper.factoryFor(.NextStep) +let factoryOne = NumberHelper.factory(for: .nextStep) let numberOne = factoryOne("1") numberOne.stringValue() -let factoryTwo = NumberHelper.factoryFor(.Swift) +let factoryTwo = NumberHelper.factory(for: .swift) let numberTwo = factoryTwo("2") numberTwo.stringValue() /*: @@ -111,7 +111,7 @@ struct DeathStar : CustomStringConvertible { init?(builder: DeathStarBuilder) { - if let x = builder.x, y = builder.y, z = builder.z { + if let x = builder.x, let y = builder.y, let z = builder.z { self.x = x self.y = y self.z = z @@ -171,16 +171,16 @@ class UnitedStatesDolar : Currency { } enum Country { - case UnitedStates, Spain, UK, Greece + case unitedStates, spain, uk, greece } enum CurrencyFactory { - static func currencyForCountry(country:Country) -> Currency? { + static func currency(for country:Country) -> Currency? { switch country { - case .Spain, .Greece : + case .spain, .greece : return Euro() - case .UnitedStates : + case .unitedStates : return UnitedStatesDolar() default: return nil @@ -193,10 +193,10 @@ enum CurrencyFactory { */ let noCurrencyCode = "No Currency Code Available" -CurrencyFactory.currencyForCountry(.Greece)?.code() ?? noCurrencyCode -CurrencyFactory.currencyForCountry(.Spain)?.code() ?? noCurrencyCode -CurrencyFactory.currencyForCountry(.UnitedStates)?.code() ?? noCurrencyCode -CurrencyFactory.currencyForCountry(.UK)?.code() ?? noCurrencyCode +CurrencyFactory.currency(for: .greece)?.code() ?? noCurrencyCode +CurrencyFactory.currency(for: .spain)?.code() ?? noCurrencyCode +CurrencyFactory.currency(for: .unitedStates)?.code() ?? noCurrencyCode +CurrencyFactory.currency(for: .uk)?.code() ?? noCurrencyCode /*: 🃏 Prototype ------------ diff --git a/Design-Patterns.playground/Pages/Creational.xcplaygroundpage/timeline.xctimeline b/Design-Patterns.playground/Pages/Creational.xcplaygroundpage/timeline.xctimeline deleted file mode 100644 index bf468af..0000000 --- a/Design-Patterns.playground/Pages/Creational.xcplaygroundpage/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/Design-Patterns.playground/Pages/Structural.xcplaygroundpage/Contents.swift b/Design-Patterns.playground/Pages/Structural.xcplaygroundpage/Contents.swift index 9450ce0..e7387ef 100644 --- a/Design-Patterns.playground/Pages/Structural.xcplaygroundpage/Contents.swift +++ b/Design-Patterns.playground/Pages/Structural.xcplaygroundpage/Contents.swift @@ -42,11 +42,11 @@ struct OldDeathStarSuperlaserTarget : OlderDeathStarSuperLaserAiming { private let target : DeathStarSuperlaserTarget var angleV:NSNumber { - return NSNumber(double: target.angleVertical) + return NSNumber(value: target.angleVertical) } var angleH:NSNumber { - return NSNumber(double: target.angleHorizontal) + return NSNumber(value: target.angleHorizontal) } init(_ target:DeathStarSuperlaserTarget) { @@ -129,13 +129,13 @@ protocol Shape { /*: Leafs */ -class Square : Shape { +final class Square : Shape { func draw(fillColor: String) { print("Drawing a Square with color \(fillColor)") } } -class Circle : Shape { +final class Circle : Shape { func draw(fillColor: String) { print("Drawing a circle with color \(fillColor)") } @@ -144,16 +144,16 @@ class Circle : Shape { /*: Composite */ -class Whiteboard : Shape { +final class Whiteboard : Shape { lazy var shapes = [Shape]() init(_ shapes:Shape...) { self.shapes = shapes } - func draw(fillColor:String) { + func draw(fillColor: String) { for shape in self.shapes { - shape.draw(fillColor) + shape.draw(fillColor: fillColor) } } } @@ -188,7 +188,7 @@ class SimpleCoffee: Coffee { class CoffeeDecorator: Coffee { private let decoratedCoffee: Coffee - private let ingredientSeparator: String = ", " + fileprivate let ingredientSeparator: String = ", " required init(decoratedCoffee: Coffee) { self.decoratedCoffee = decoratedCoffee @@ -203,7 +203,7 @@ class CoffeeDecorator: Coffee { } } -class Milk: CoffeeDecorator { +final class Milk: CoffeeDecorator { required init(decoratedCoffee: Coffee) { super.init(decoratedCoffee: decoratedCoffee) } @@ -217,7 +217,7 @@ class Milk: CoffeeDecorator { } } -class WhipCoffee: CoffeeDecorator { +final class WhipCoffee: CoffeeDecorator { required init(decoratedCoffee: Coffee) { super.init(decoratedCoffee: decoratedCoffee) } @@ -249,66 +249,66 @@ The facade pattern is used to define a simplified interface to a more complex su */ enum Eternal { - static func setObject(value: AnyObject!, forKey defaultName: String!) { - let defaults:NSUserDefaults = NSUserDefaults.standardUserDefaults() - defaults.setObject(value, forKey:defaultName) + static func set(_ object: Any, forKey defaultName: String) { + let defaults: UserDefaults = UserDefaults.standard + defaults.set(object, forKey:defaultName) defaults.synchronize() } - static func objectForKey(defaultName: String!) -> AnyObject! { - let defaults:NSUserDefaults = NSUserDefaults.standardUserDefaults() - - return defaults.objectForKey(defaultName) + static func object(forKey key: String) -> AnyObject! { + let defaults: UserDefaults = UserDefaults.standard + return defaults.object(forKey: key) as AnyObject! } } /*: ### Usage */ -Eternal.setObject("Disconnect me. I’d rather be nothing", forKey:"Bishop") -Eternal.objectForKey("Bishop") +Eternal.set("Disconnect me. I’d rather be nothing", forKey:"Bishop") +Eternal.object(forKey: "Bishop") /*: ## 🍃 Flyweight The flyweight pattern is used to minimize memory usage or computational expenses by sharing as much as possible with other similar objects. ### Example */ // Instances of CoffeeFlavour will be the Flyweights -class CoffeeFlavor : Printable { - var flavor: String +final class SpecialityCoffee: CustomStringConvertible { + var origin: String var description: String { get { - return flavor + return origin } } - init(flavor: String) { - self.flavor = flavor + init(origin: String) { + self.origin = origin } } // Menu acts as a factory and cache for CoffeeFlavour flyweight objects -class Menu { - private var flavors: [String: CoffeeFlavor] = [:] +final class Menu { + private var coffeeAvailable: [String: SpecialityCoffee] = [:] - func lookup(flavor: String) -> CoffeeFlavor { - if flavors.indexForKey(flavor) == nil { - flavors[flavor] = CoffeeFlavor(flavor: flavor) + func lookup(origin: String) -> SpecialityCoffee? { + if coffeeAvailable.index(forKey: origin) == nil { + coffeeAvailable[origin] = SpecialityCoffee(origin: origin) } - return flavors[flavor]! + + return coffeeAvailable[origin] } } -class CoffeeShop { - private var orders: [Int: CoffeeFlavor] = [:] +final class CoffeeShop { + private var orders: [Int: SpecialityCoffee] = [:] private var menu = Menu() - func takeOrder(#flavor: String, table: Int) { - orders[table] = menu.lookup(flavor) + func takeOrder(origin: String, table: Int) { + orders[table] = menu.lookup(origin: origin) } func serve() { - for (table, flavor) in orders { - println("Serving \(flavor) to table \(table)") + for (table, origin) in orders { + print("Serving \(origin) to table \(table)") } } } @@ -317,18 +317,8 @@ class CoffeeShop { */ let coffeeShop = CoffeeShop() -coffeeShop.takeOrder(flavor: "Cappuccino", table: 1) -coffeeShop.takeOrder(flavor: "Frappe", table: 3); -coffeeShop.takeOrder(flavor: "Espresso", table: 2); -coffeeShop.takeOrder(flavor: "Frappe", table: 15); -coffeeShop.takeOrder(flavor: "Cappuccino", table: 10); -coffeeShop.takeOrder(flavor: "Frappe", table: 8); -coffeeShop.takeOrder(flavor: "Espresso", table: 7); -coffeeShop.takeOrder(flavor: "Cappuccino", table: 4); -coffeeShop.takeOrder(flavor: "Espresso", table: 9); -coffeeShop.takeOrder(flavor: "Frappe", table: 12); -coffeeShop.takeOrder(flavor: "Cappuccino", table: 13); -coffeeShop.takeOrder(flavor: "Espresso", table: 5); +coffeeShop.takeOrder(origin: "Yirgacheffe, Ethiopia", table: 1) +coffeeShop.takeOrder(origin: "Buziraguhindwa, Burundi", table: 3) coffeeShop.serve() /*: @@ -341,11 +331,11 @@ Protection proxy is restricting access. ### Example */ protocol DoorOperator { - func openDoors(doors: String) -> String + func open(doors: String) -> String } class HAL9000 : DoorOperator { - func openDoors(doors: String) -> String { + func open(doors: String) -> String { return ("HAL9000: Affirmative, Dave. I read you. Opened \(doors).") } } @@ -353,9 +343,9 @@ class HAL9000 : DoorOperator { class CurrentComputer : DoorOperator { private var computer: HAL9000! - func authenticateWithPassword(pass: String) -> Bool { + func authenticate(password: String) -> Bool { - guard pass == "pass" else { + guard password == "pass" else { return false; } @@ -364,25 +354,25 @@ class CurrentComputer : DoorOperator { return true } - func openDoors(doors: String) -> String { + func open(doors: String) -> String { guard computer != nil else { return "Access Denied. I'm afraid I can't do that." } - return computer.openDoors(doors) + return computer.open(doors: doors) } } /*: ### Usage */ let computer = CurrentComputer() -let doors = "Pod Bay Doors" +let podBay = "Pod Bay Doors" -computer.openDoors(doors) +computer.open(doors: podBay) -computer.authenticateWithPassword("pass") -computer.openDoors(doors) +computer.authenticate(password: "pass") +computer.open(doors: podBay) /*: 🍬 Virtual Proxy ---------------- diff --git a/Design-Patterns.playground/Pages/Structural.xcplaygroundpage/timeline.xctimeline b/Design-Patterns.playground/Pages/Structural.xcplaygroundpage/timeline.xctimeline deleted file mode 100644 index bf468af..0000000 --- a/Design-Patterns.playground/Pages/Structural.xcplaygroundpage/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..0308481 --- /dev/null +++ b/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,5 @@ + + +- [ ] Do not change the `.playground` nor `README.md` manually. +- [ ] Go to `/source` and edit .swift files. +- [ ] Run: `generate-playground.sh` \ No newline at end of file diff --git a/README.md b/README.md index 54c3c35..e340b5f 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,12 @@ -Design Patterns implemented in Swift 2.2 +Design Patterns implemented in Swift 3.0 ======================================== -A short cheat-sheet with Xcode 7.3 Playground ([Design-Patterns.playground.zip](https://raw.githubusercontent.com/ochococo/Design-Patterns-In-Swift/master/Design-Patterns.playground.zip)). +A short cheat-sheet with Xcode 8.2 Playground ([Design-Patterns.playground.zip](https://raw.githubusercontent.com/ochococo/Design-Patterns-In-Swift/master/Design-Patterns.playground.zip)). 👷 Project maintained by: [@nsmeme](http://twitter.com/nsmeme) (Oktawian Chojnacki) +🚀 How to generate README, Playground and zip from source: [GENERATE.md](https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/GENERATE.md) + ## Table of Contents * [Behavioral](#behavioral) @@ -13,6 +15,7 @@ A short cheat-sheet with Xcode 7.3 Playground ([Design-Patterns.playground.zip]( ```swift + Behavioral | [Creational](Creational) | [Structural](Structural) @@ -40,60 +43,63 @@ The chain of responsibility pattern is used to process varied requests, each of ```swift -class MoneyPile { +final class MoneyPile { + let value: Int var quantity: Int var nextPile: MoneyPile? - + init(value: Int, quantity: Int, nextPile: MoneyPile?) { self.value = value self.quantity = quantity self.nextPile = nextPile } - - func canWithdraw(v: Int) -> Bool { - var v = v + func canWithdraw(amount: Int) -> Bool { + + var amount = amount func canTakeSomeBill(want: Int) -> Bool { return (want / self.value) > 0 } - - var q = self.quantity - while canTakeSomeBill(v) { + var quantity = self.quantity + + while canTakeSomeBill(want: amount) { - if q == 0 { + if quantity == 0 { break } - v -= self.value - q -= 1 + amount -= self.value + quantity -= 1 } - if v == 0 { + guard amount > 0 else { return true - } else if let next = self.nextPile { - return next.canWithdraw(v) + } + + if let next = self.nextPile { + return next.canWithdraw(amount: amount) } return false } } -class ATM { +final class ATM { private var hundred: MoneyPile private var fifty: MoneyPile private var twenty: MoneyPile private var ten: MoneyPile - + private var startPile: MoneyPile { return self.hundred } - - init(hundred: MoneyPile, - fifty: MoneyPile, - twenty: MoneyPile, + + init(hundred: MoneyPile, + fifty: MoneyPile, + twenty: MoneyPile, ten: MoneyPile) { self.hundred = hundred @@ -101,9 +107,9 @@ class ATM { self.twenty = twenty self.ten = ten } - - func canWithdraw(value: Int) -> String { - return "Can withdraw: \(self.startPile.canWithdraw(value))" + + func canWithdraw(amount: Int) -> String { + return "Can withdraw: \(self.startPile.canWithdraw(amount: amount))" } } ``` @@ -120,17 +126,14 @@ let hundred = MoneyPile(value: 100, quantity: 1, nextPile: fifty) // Build ATM. var atm = ATM(hundred: hundred, fifty: fifty, twenty: twenty, ten: ten) -atm.canWithdraw(310) // Cannot because ATM has only 300 -atm.canWithdraw(100) // Can withdraw - 1x100 -atm.canWithdraw(165) // Cannot withdraw because ATM doesn't has bill with value of 5 -atm.canWithdraw(30) // Can withdraw - 1x20, 2x10 +atm.canWithdraw(amount: 310) // Cannot because ATM has only 300 +atm.canWithdraw(amount: 100) // Can withdraw - 1x100 +atm.canWithdraw(amount: 165) // Cannot withdraw because ATM doesn't has bill with value of 5 +atm.canWithdraw(amount: 30) // Can withdraw - 1x20, 2x10 ``` >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Chain-Of-Responsibility) -```swift - -``` 👫 Command ---------- @@ -209,68 +212,68 @@ The interpreter pattern is used to evaluate sentences in a language. ```swift -protocol IntegerExp { - func evaluate(context: IntegerContext) -> Int - func replace(character: Character, integerExp: IntegerExp) -> IntegerExp - func copy() -> IntegerExp +protocol IntegerExpression { + func evaluate(_ context: IntegerContext) -> Int + func replace(character: Character, integerExpression: IntegerExpression) -> IntegerExpression + func copied() -> IntegerExpression } -class IntegerContext { +final class IntegerContext { private var data: [Character:Int] = [:] - + func lookup(name: Character) -> Int { return self.data[name]! } - - func assign(integerVarExp: IntegerVarExp, value: Int) { - self.data[integerVarExp.name] = value + + func assign(expression: IntegerVariableExpression, value: Int) { + self.data[expression.name] = value } } -class IntegerVarExp: IntegerExp { +final class IntegerVariableExpression: IntegerExpression { let name: Character - + init(name: Character) { self.name = name } - - func evaluate(context: IntegerContext) -> Int { - return context.lookup(self.name) + + func evaluate(_ context: IntegerContext) -> Int { + return context.lookup(name: self.name) } - - func replace(name: Character, integerExp: IntegerExp) -> IntegerExp { + + func replace(character name: Character, integerExpression: IntegerExpression) -> IntegerExpression { if name == self.name { - return integerExp.copy() + return integerExpression.copied() } else { - return IntegerVarExp(name: self.name) + return IntegerVariableExpression(name: self.name) } } - - func copy() -> IntegerExp { - return IntegerVarExp(name: self.name) + + func copied() -> IntegerExpression { + return IntegerVariableExpression(name: self.name) } } -class AddExp: IntegerExp { - private var operand1: IntegerExp - private var operand2: IntegerExp - - init(op1: IntegerExp, op2: IntegerExp) { +final class AddExpression: IntegerExpression { + private var operand1: IntegerExpression + private var operand2: IntegerExpression + + init(op1: IntegerExpression, op2: IntegerExpression) { self.operand1 = op1 self.operand2 = op2 } - - func evaluate(context: IntegerContext) -> Int { + + func evaluate(_ context: IntegerContext) -> Int { return self.operand1.evaluate(context) + self.operand2.evaluate(context) } - - func replace(character: Character, integerExp: IntegerExp) -> IntegerExp { - return AddExp(op1: operand1.replace(character, integerExp: integerExp), - op2: operand2.replace(character, integerExp: integerExp)) + + func replace(character: Character, integerExpression: IntegerExpression) -> IntegerExpression { + return AddExpression(op1: operand1.replace(character: character, integerExpression: integerExpression), + op2: operand2.replace(character: character, integerExpression: integerExpression)) } - - func copy() -> IntegerExp { - return AddExp(op1: self.operand1, op2: self.operand2) + + func copied() -> IntegerExpression { + return AddExpression(op1: self.operand1, op2: self.operand2) } } ``` @@ -279,28 +282,23 @@ class AddExp: IntegerExp { ```swift -var expression: IntegerExp? -var intContext = IntegerContext() +var context = IntegerContext() -var a = IntegerVarExp(name: "A") -var b = IntegerVarExp(name: "B") -var c = IntegerVarExp(name: "C") +var a = IntegerVariableExpression(name: "A") +var b = IntegerVariableExpression(name: "B") +var c = IntegerVariableExpression(name: "C") -expression = AddExp(op1: a, op2: AddExp(op1: b, op2: c)) // a + (b + c) +var expression = AddExpression(op1: a, op2: AddExpression(op1: b, op2: c)) // a + (b + c) -intContext.assign(a, value: 2) -intContext.assign(b, value: 1) -intContext.assign(c, value: 3) +context.assign(expression: a, value: 2) +context.assign(expression: b, value: 1) +context.assign(expression: c, value: 3) -var result = expression?.evaluate(intContext) +var result = expression.evaluate(context) ``` >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Interpreter) -```swift - -``` - 🍫 Iterator ----------- @@ -310,16 +308,32 @@ The iterator pattern is used to provide a standard interface for traversing a co ```swift -struct NovellasCollection { - let novellas: [T] +struct Novella { + let name: String } -extension NovellasCollection: SequenceType { - typealias Generator = AnyGenerator - - func generate() -> AnyGenerator { - var i = 0 - return AnyGenerator { i += 1; return i >= self.novellas.count ? nil : self.novellas[i] } +struct Novellas { + let novellas: [Novella] +} + +struct NovellasIterator: IteratorProtocol { + + private var current = 0 + private let novellas: [Novella] + + init(novellas: [Novella]) { + self.novellas = novellas + } + + mutating func next() -> Novella? { + defer { current += 1 } + return novellas.count > current ? novellas[current] : nil + } +} + +extension Novellas: Sequence { + func makeIterator() -> NovellasIterator { + return NovellasIterator(novellas: novellas) } } ``` @@ -328,7 +342,7 @@ extension NovellasCollection: SequenceType { ```swift -let greatNovellas = NovellasCollection(novellas:["Mist"]) +let greatNovellas = Novellas(novellas: [Novella(name: "The Mist")] ) for novella in greatNovellas { print("I've read: \(novella)") @@ -344,72 +358,59 @@ The mediator pattern is used to reduce coupling between classes that communicate ```swift +struct Programmer { -class Colleague { let name: String - let mediator: Mediator - - init(name: String, mediator: Mediator) { + + init(name: String) { self.name = name - self.mediator = mediator } - - func send(message: String) { - mediator.send(message, colleague: self) - } - + func receive(message: String) { - assert(false, "Method should be overriden") + print("\(name) received: \(message)") } } -protocol Mediator { - func send(message: String, colleague: Colleague) +protocol MessageSending { + func send(message: String) } -class MessageMediator: Mediator { - private var colleagues: [Colleague] = [] - - func addColleague(colleague: Colleague) { - colleagues.append(colleague) - } - - func send(message: String, colleague: Colleague) { - for c in colleagues { - if c !== colleague { //for simplicity we compare object references - c.receive(message) - } - } +final class MessageMediator: MessageSending { + + private var recipients: [Programmer] = [] + + func add(recipient: Programmer) { + recipients.append(recipient) } -} -class ConcreteColleague: Colleague { - override func receive(message: String) { - print("Colleague \(name) received: \(message)") + func send(message: String) { + for recipient in recipients { + recipient.receive(message: message) + } } } - ``` ### Usage ```swift +func spamMonster(message: String, worker: MessageSending) { + worker.send(message: message) +} let messagesMediator = MessageMediator() -let user0 = ConcreteColleague(name: "0", mediator: messagesMediator) -let user1 = ConcreteColleague(name: "1", mediator: messagesMediator) -messagesMediator.addColleague(user0) -messagesMediator.addColleague(user1) -user0.send("Hello") // user1 receives message +let user0 = Programmer(name: "Linus Torvalds") +let user1 = Programmer(name: "Avadis 'Avie' Tevanian") +messagesMediator.add(recipient: user0) +messagesMediator.add(recipient: user1) + +spamMonster(message: "I'd Like to Add you to My Professional Network", worker: messagesMediator) ``` >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Mediator) -```swift - -``` 💾 Memento ---------- @@ -420,28 +421,45 @@ The memento pattern is used to capture the current state of an object and store ```swift -typealias Memento = Dictionary - -let DPMementoKeyChapter = "com.valve.halflife.chapter" -let DPMementoKeyWeapon = "com.valve.halflife.weapon" -let DPMementoGameState = "com.valve.halflife.state" +typealias Memento = NSDictionary ``` Originator ```swift -class GameState { - var chapter: String = "" - var weapon: String = "" +protocol MementoConvertible { + var memento: Memento { get } + init?(memento: Memento) +} + +struct GameState: MementoConvertible { - func toMemento() -> Memento { - return [ DPMementoKeyChapter:chapter, DPMementoKeyWeapon:weapon ] + private struct Keys { + static let chapter = "com.valve.halflife.chapter" + static let weapon = "com.valve.halflife.weapon" } - func restoreFromMemento(memento: Memento) { - chapter = memento[DPMementoKeyChapter] as? String ?? "n/a" - weapon = memento[DPMementoKeyWeapon] as? String ?? "n/a" + var chapter: String + var weapon: String + + init(chapter: String, weapon: String) { + self.chapter = chapter + self.weapon = weapon + } + + init?(memento: Memento) { + guard let mementoChapter = memento[Keys.chapter] as? String, + let mementoWeapon = memento[Keys.weapon] as? String else { + return nil + } + + chapter = mementoChapter + weapon = mementoWeapon + } + + var memento: Memento { + return [ Keys.chapter: chapter, Keys.weapon: weapon ] } } ``` @@ -451,16 +469,16 @@ Caretaker ```swift enum CheckPoint { - static func saveState(memento: Memento, keyName: String = DPMementoGameState) { - let defaults = NSUserDefaults.standardUserDefaults() - defaults.setObject(memento, forKey: keyName) + static func save(_ state: MementoConvertible, saveName: String) { + let defaults = UserDefaults.standard + defaults.set(state.memento, forKey: saveName) defaults.synchronize() } - static func restorePreviousState(keyName keyName: String = DPMementoGameState) -> Memento { - let defaults = NSUserDefaults.standardUserDefaults() + static func restore(saveName: String) -> Memento? { + let defaults = UserDefaults.standard - return defaults.objectForKey(keyName) as? Memento ?? Memento() + return defaults.object(forKey: saveName) as? Memento } } ``` @@ -469,33 +487,30 @@ enum CheckPoint { ```swift -var gameState = GameState() -gameState.restoreFromMemento(CheckPoint.restorePreviousState()) - -gameState.chapter = "Black Mesa Inbound" -gameState.weapon = "Crowbar" -CheckPoint.saveState(gameState.toMemento()) +var gameState = GameState(chapter: "Black Mesa Inbound", weapon: "Crowbar") gameState.chapter = "Anomalous Materials" gameState.weapon = "Glock 17" -gameState.restoreFromMemento(CheckPoint.restorePreviousState()) +CheckPoint.save(gameState, saveName: "gameState1") gameState.chapter = "Unforeseen Consequences" gameState.weapon = "MP5" -CheckPoint.saveState(gameState.toMemento(), keyName: "gameState2") +CheckPoint.save(gameState, saveName: "gameState2") gameState.chapter = "Office Complex" gameState.weapon = "Crossbow" -CheckPoint.saveState(gameState.toMemento()) - -gameState.restoreFromMemento(CheckPoint.restorePreviousState(keyName: "gameState2")) +CheckPoint.save(gameState, saveName: "gameState3") +if let memento = CheckPoint.restore(saveName: "gameState1") { + let finalState = GameState(memento: memento) + dump(finalState) +} ``` 👓 Observer ----------- -The observer pattern is used to allow an object to publish changes to its state. +The observer pattern is used to allow an object to publish changes to its state. Other objects subscribe to be immediately notified of any changes. ### Example @@ -503,32 +518,34 @@ Other objects subscribe to be immediately notified of any changes. ```swift protocol PropertyObserver : class { - func willChangePropertyName(propertyName:String, newPropertyValue:AnyObject?) - func didChangePropertyName(propertyName:String, oldPropertyValue:AnyObject?) + func willChange(propertyName: String, newPropertyValue: Any?) + func didChange(propertyName: String, oldPropertyValue: Any?) } -class TestChambers { +final class TestChambers { weak var observer:PropertyObserver? + private let testChamberNumberName = "testChamberNumber" + var testChamberNumber: Int = 0 { willSet(newValue) { - observer?.willChangePropertyName("testChamberNumber", newPropertyValue:newValue) + observer?.willChange(propertyName: testChamberNumberName, newPropertyValue: newValue) } didSet { - observer?.didChangePropertyName("testChamberNumber", oldPropertyValue:oldValue) + observer?.didChange(propertyName: testChamberNumberName, oldPropertyValue: oldValue) } } } -class Observer : PropertyObserver { - func willChangePropertyName(propertyName: String, newPropertyValue: AnyObject?) { +final class Observer : PropertyObserver { + func willChange(propertyName: String, newPropertyValue: Any?) { if newPropertyValue as? Int == 1 { print("Okay. Look. We both said a lot of things that you're going to regret.") } } - func didChangePropertyName(propertyName: String, oldPropertyValue: AnyObject?) { + func didChange(propertyName: String, oldPropertyValue: Any?) { if oldPropertyValue as? Int == 0 { print("Sorry about the mess. I've really let the place go since you killed me.") } @@ -543,44 +560,41 @@ class Observer : PropertyObserver { var observerInstance = Observer() var testChambers = TestChambers() testChambers.observer = observerInstance -testChambers.testChamberNumber++ +testChambers.testChamberNumber += 1 ``` >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Observer) -```swift - -``` 🐉 State --------- -The state pattern is used to alter the behaviour of an object as its internal state changes. +The state pattern is used to alter the behaviour of an object as its internal state changes. The pattern allows the class for an object to apparently change at run-time. ### Example ```swift -class Context { +final class Context { private var state: State = UnauthorizedState() var isAuthorized: Bool { - get { return state.isAuthorized(self) } + get { return state.isAuthorized(context: self) } } var userId: String? { - get { return state.userId(self) } + get { return state.userId(context: self) } } - func changeStateToAuthorized(userId userId: String) { + func changeStateToAuthorized(userId: String) { state = AuthorizedState(userId: userId) } func changeStateToUnauthorized() { state = UnauthorizedState() } - + } protocol State { @@ -609,19 +623,16 @@ class AuthorizedState: State { ```swift -let context = Context() -(context.isAuthorized, context.userId) -context.changeStateToAuthorized(userId: "admin") -(context.isAuthorized, context.userId) // now logged in as "admin" -context.changeStateToUnauthorized() -(context.isAuthorized, context.userId) +let userContext = Context() +(userContext.isAuthorized, userContext.userId) +userContext.changeStateToAuthorized(userId: "admin") +(userContext.isAuthorized, userContext.userId) // now logged in as "admin" +userContext.changeStateToUnauthorized() +(userContext.isAuthorized, userContext.userId) ``` >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-State) -```swift - -``` 💡 Strategy ----------- @@ -633,31 +644,31 @@ The strategy pattern is used to create an interchangeable family of algorithms f ```swift protocol PrintStrategy { - func printString(string: String) -> String + func print(_ string: String) -> String } -class Printer { +final class Printer { - let strategy: PrintStrategy - - func printString(string: String) -> String { - return self.strategy.printString(string) + private let strategy: PrintStrategy + + func print(_ string: String) -> String { + return self.strategy.print(string) } - + init(strategy: PrintStrategy) { self.strategy = strategy } } -class UpperCaseStrategy : PrintStrategy { - func printString(string:String) -> String { - return string.uppercaseString +final class UpperCaseStrategy: PrintStrategy { + func print(_ string: String) -> String { + return string.uppercased() } } -class LowerCaseStrategy : PrintStrategy { - func printString(string:String) -> String { - return string.lowercaseString +final class LowerCaseStrategy: PrintStrategy { + func print(_ string:String) -> String { + return string.lowercased() } } ``` @@ -666,19 +677,15 @@ class LowerCaseStrategy : PrintStrategy { ```swift -var lower = Printer(strategy:LowerCaseStrategy()) -lower.printString("O tempora, o mores!") +var lower = Printer(strategy: LowerCaseStrategy()) +lower.print("O tempora, o mores!") -var upper = Printer(strategy:UpperCaseStrategy()) -upper.printString("O tempora, o mores!") +var upper = Printer(strategy: UpperCaseStrategy()) +upper.print("O tempora, o mores!") ``` >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Strategy) -```swift - -``` - 🏃 Visitor ---------- @@ -692,40 +699,51 @@ protocol PlanetVisitor { func visit(planet: PlanetAlderaan) func visit(planet: PlanetCoruscant) func visit(planet: PlanetTatooine) + func visit(planet: PlanetJedah) } protocol Planet { func accept(visitor: PlanetVisitor) } +class PlanetJedah: Planet { + func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) } +} + class PlanetAlderaan: Planet { - func accept(visitor: PlanetVisitor) { visitor.visit(self) } + func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) } } + class PlanetCoruscant: Planet { - func accept(visitor: PlanetVisitor) { visitor.visit(self) } + func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) } } + class PlanetTatooine: Planet { - func accept(visitor: PlanetVisitor) { visitor.visit(self) } + func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) } } + + class NameVisitor: PlanetVisitor { var name = "" func visit(planet: PlanetAlderaan) { name = "Alderaan" } func visit(planet: PlanetCoruscant) { name = "Coruscant" } func visit(planet: PlanetTatooine) { name = "Tatooine" } + func visit(planet: PlanetJedah) { name = "Jedah" } } + ``` ### Usage ```swift -let planets: [Planet] = [PlanetAlderaan(), PlanetCoruscant(), PlanetTatooine()] +let planets: [Planet] = [PlanetAlderaan(), PlanetCoruscant(), PlanetTatooine(), PlanetJedah()] let names = planets.map { (planet: Planet) -> String in let visitor = NameVisitor() - planet.accept(visitor) + planet.accept(visitor: visitor) return visitor.name } @@ -761,10 +779,6 @@ The abstract factory pattern is used to provide a client with a set of related o The "family" of objects created by the factory are determined at run-time. ### Example - -```swift - -``` Protocols @@ -780,24 +794,24 @@ typealias NumberFactory = (String) -> Decimal // Number implementations with factory methods -struct NextStepNumber : Decimal { - private var nextStepNumber : NSNumber +struct NextStepNumber: Decimal { + private var nextStepNumber: NSNumber func stringValue() -> String { return nextStepNumber.stringValue } // factory - static func make(string : String) -> Decimal { - return NextStepNumber(nextStepNumber:NSNumber(longLong:(string as NSString).longLongValue)) + static func make(string: String) -> Decimal { + return NextStepNumber(nextStepNumber: NSNumber(value: (string as NSString).longLongValue)) } } struct SwiftNumber : Decimal { - private var swiftInt : Int + private var swiftInt: Int func stringValue() -> String { return "\(swiftInt)" } // factory - static func make(string : String) -> Decimal { + static func make(string: String) -> Decimal { return SwiftNumber(swiftInt:(string as NSString).integerValue) } } @@ -808,15 +822,15 @@ Abstract factory ```swift enum NumberType { - case NextStep, Swift + case nextStep, swift } enum NumberHelper { - static func factoryFor(type : NumberType) -> NumberFactory { + static func factory(for type: NumberType) -> NumberFactory { switch type { - case .NextStep: + case .nextStep: return NextStepNumber.make - case .Swift: + case .swift: return SwiftNumber.make } } @@ -827,11 +841,11 @@ enum NumberHelper { ```swift -let factoryOne = NumberHelper.factoryFor(.NextStep) +let factoryOne = NumberHelper.factory(for: .nextStep) let numberOne = factoryOne("1") numberOne.stringValue() -let factoryTwo = NumberHelper.factoryFor(.Swift) +let factoryTwo = NumberHelper.factory(for: .swift) let numberTwo = factoryTwo("2") numberTwo.stringValue() ``` @@ -867,7 +881,7 @@ struct DeathStar : CustomStringConvertible { init?(builder: DeathStarBuilder) { - if let x = builder.x, y = builder.y, z = builder.z { + if let x = builder.x, let y = builder.y, let z = builder.z { self.x = x self.y = y self.z = z @@ -897,10 +911,6 @@ let deathStar = DeathStar(builder:empire) >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Builder) -```swift - -``` - 🏭 Factory Method ----------------- @@ -936,16 +946,16 @@ class UnitedStatesDolar : Currency { } enum Country { - case UnitedStates, Spain, UK, Greece + case unitedStates, spain, uk, greece } enum CurrencyFactory { - static func currencyForCountry(country:Country) -> Currency? { + static func currency(for country:Country) -> Currency? { switch country { - case .Spain, .Greece : + case .spain, .greece : return Euro() - case .UnitedStates : + case .unitedStates : return UnitedStatesDolar() default: return nil @@ -961,10 +971,10 @@ enum CurrencyFactory { let noCurrencyCode = "No Currency Code Available" -CurrencyFactory.currencyForCountry(.Greece)?.code() ?? noCurrencyCode -CurrencyFactory.currencyForCountry(.Spain)?.code() ?? noCurrencyCode -CurrencyFactory.currencyForCountry(.UnitedStates)?.code() ?? noCurrencyCode -CurrencyFactory.currencyForCountry(.UK)?.code() ?? noCurrencyCode +CurrencyFactory.currency(for: .greece)?.code() ?? noCurrencyCode +CurrencyFactory.currency(for: .spain)?.code() ?? noCurrencyCode +CurrencyFactory.currency(for: .unitedStates)?.code() ?? noCurrencyCode +CurrencyFactory.currency(for: .uk)?.code() ?? noCurrencyCode ``` 🃏 Prototype @@ -1009,10 +1019,6 @@ Eduardo.name = "Eduardo" >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Prototype) -```swift - -``` - 💍 Singleton ------------ @@ -1094,11 +1100,11 @@ struct OldDeathStarSuperlaserTarget : OlderDeathStarSuperLaserAiming { private let target : DeathStarSuperlaserTarget var angleV:NSNumber { - return NSNumber(double: target.angleVertical) + return NSNumber(value: target.angleVertical) } var angleH:NSNumber { - return NSNumber(double: target.angleHorizontal) + return NSNumber(value: target.angleHorizontal) } init(_ target:DeathStarSuperlaserTarget) { @@ -1120,10 +1126,6 @@ oldFormat.angleV >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Adapter) -```swift - -``` - 🌉 Bridge ---------- @@ -1202,13 +1204,13 @@ Leafs ```swift -class Square : Shape { +final class Square : Shape { func draw(fillColor: String) { print("Drawing a Square with color \(fillColor)") } } -class Circle : Shape { +final class Circle : Shape { func draw(fillColor: String) { print("Drawing a circle with color \(fillColor)") } @@ -1220,16 +1222,16 @@ Composite ```swift -class Whiteboard : Shape { +final class Whiteboard : Shape { lazy var shapes = [Shape]() init(_ shapes:Shape...) { self.shapes = shapes } - func draw(fillColor:String) { + func draw(fillColor: String) { for shape in self.shapes { - shape.draw(fillColor) + shape.draw(fillColor: fillColor) } } } @@ -1270,7 +1272,7 @@ class SimpleCoffee: Coffee { class CoffeeDecorator: Coffee { private let decoratedCoffee: Coffee - private let ingredientSeparator: String = ", " + fileprivate let ingredientSeparator: String = ", " required init(decoratedCoffee: Coffee) { self.decoratedCoffee = decoratedCoffee @@ -1285,7 +1287,7 @@ class CoffeeDecorator: Coffee { } } -class Milk: CoffeeDecorator { +final class Milk: CoffeeDecorator { required init(decoratedCoffee: Coffee) { super.init(decoratedCoffee: decoratedCoffee) } @@ -1299,7 +1301,7 @@ class Milk: CoffeeDecorator { } } -class WhipCoffee: CoffeeDecorator { +final class WhipCoffee: CoffeeDecorator { required init(decoratedCoffee: Coffee) { super.init(decoratedCoffee: decoratedCoffee) } @@ -1337,16 +1339,15 @@ The facade pattern is used to define a simplified interface to a more complex su enum Eternal { - static func setObject(value: AnyObject!, forKey defaultName: String!) { - let defaults:NSUserDefaults = NSUserDefaults.standardUserDefaults() - defaults.setObject(value, forKey:defaultName) + static func set(_ object: Any, forKey defaultName: String) { + let defaults: UserDefaults = UserDefaults.standard + defaults.set(object, forKey:defaultName) defaults.synchronize() } - static func objectForKey(defaultName: String!) -> AnyObject! { - let defaults:NSUserDefaults = NSUserDefaults.standardUserDefaults() - - return defaults.objectForKey(defaultName) + static func object(forKey key: String) -> AnyObject! { + let defaults: UserDefaults = UserDefaults.standard + return defaults.object(forKey: key) as AnyObject! } } @@ -1356,8 +1357,8 @@ enum Eternal { ```swift -Eternal.setObject("Disconnect me. I’d rather be nothing", forKey:"Bishop") -Eternal.objectForKey("Bishop") +Eternal.set("Disconnect me. I’d rather be nothing", forKey:"Bishop") +Eternal.object(forKey: "Bishop") ``` ## 🍃 Flyweight @@ -1367,42 +1368,43 @@ The flyweight pattern is used to minimize memory usage or computational expenses ```swift // Instances of CoffeeFlavour will be the Flyweights -class CoffeeFlavor : Printable { - var flavor: String +final class SpecialityCoffee: CustomStringConvertible { + var origin: String var description: String { get { - return flavor + return origin } } - init(flavor: String) { - self.flavor = flavor + init(origin: String) { + self.origin = origin } } // Menu acts as a factory and cache for CoffeeFlavour flyweight objects -class Menu { - private var flavors: [String: CoffeeFlavor] = [:] +final class Menu { + private var coffeeAvailable: [String: SpecialityCoffee] = [:] - func lookup(flavor: String) -> CoffeeFlavor { - if flavors.indexForKey(flavor) == nil { - flavors[flavor] = CoffeeFlavor(flavor: flavor) + func lookup(origin: String) -> SpecialityCoffee? { + if coffeeAvailable.index(forKey: origin) == nil { + coffeeAvailable[origin] = SpecialityCoffee(origin: origin) } - return flavors[flavor]! + + return coffeeAvailable[origin] } } -class CoffeeShop { - private var orders: [Int: CoffeeFlavor] = [:] +final class CoffeeShop { + private var orders: [Int: SpecialityCoffee] = [:] private var menu = Menu() - func takeOrder(#flavor: String, table: Int) { - orders[table] = menu.lookup(flavor) + func takeOrder(origin: String, table: Int) { + orders[table] = menu.lookup(origin: origin) } func serve() { - for (table, flavor) in orders { - println("Serving \(flavor) to table \(table)") + for (table, origin) in orders { + print("Serving \(origin) to table \(table)") } } } @@ -1414,18 +1416,8 @@ class CoffeeShop { let coffeeShop = CoffeeShop() -coffeeShop.takeOrder(flavor: "Cappuccino", table: 1) -coffeeShop.takeOrder(flavor: "Frappe", table: 3); -coffeeShop.takeOrder(flavor: "Espresso", table: 2); -coffeeShop.takeOrder(flavor: "Frappe", table: 15); -coffeeShop.takeOrder(flavor: "Cappuccino", table: 10); -coffeeShop.takeOrder(flavor: "Frappe", table: 8); -coffeeShop.takeOrder(flavor: "Espresso", table: 7); -coffeeShop.takeOrder(flavor: "Cappuccino", table: 4); -coffeeShop.takeOrder(flavor: "Espresso", table: 9); -coffeeShop.takeOrder(flavor: "Frappe", table: 12); -coffeeShop.takeOrder(flavor: "Cappuccino", table: 13); -coffeeShop.takeOrder(flavor: "Espresso", table: 5); +coffeeShop.takeOrder(origin: "Yirgacheffe, Ethiopia", table: 1) +coffeeShop.takeOrder(origin: "Buziraguhindwa, Burundi", table: 3) coffeeShop.serve() ``` @@ -1441,11 +1433,11 @@ Protection proxy is restricting access. ```swift protocol DoorOperator { - func openDoors(doors: String) -> String + func open(doors: String) -> String } class HAL9000 : DoorOperator { - func openDoors(doors: String) -> String { + func open(doors: String) -> String { return ("HAL9000: Affirmative, Dave. I read you. Opened \(doors).") } } @@ -1453,9 +1445,9 @@ class HAL9000 : DoorOperator { class CurrentComputer : DoorOperator { private var computer: HAL9000! - func authenticateWithPassword(pass: String) -> Bool { + func authenticate(password: String) -> Bool { - guard pass == "pass" else { + guard password == "pass" else { return false; } @@ -1464,13 +1456,13 @@ class CurrentComputer : DoorOperator { return true } - func openDoors(doors: String) -> String { + func open(doors: String) -> String { guard computer != nil else { return "Access Denied. I'm afraid I can't do that." } - return computer.openDoors(doors) + return computer.open(doors: doors) } } ``` @@ -1480,12 +1472,12 @@ class CurrentComputer : DoorOperator { ```swift let computer = CurrentComputer() -let doors = "Pod Bay Doors" +let podBay = "Pod Bay Doors" -computer.openDoors(doors) +computer.open(doors: podBay) -computer.authenticateWithPassword("pass") -computer.openDoors(doors) +computer.authenticate(password: "pass") +computer.open(doors: podBay) ``` 🍬 Virtual Proxy @@ -1530,8 +1522,3 @@ Info ==== 📖 Descriptions from: [Gang of Four Design Patterns Reference Sheet](http://www.blackwasp.co.uk/GangOfFour.aspx) - -🚀 How to generate playground (+zip) from source: [GENERATE.md](https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/GENERATE.md) - - -```swift diff --git a/source/behavioral/visitor.swift b/source/behavioral/visitor.swift index 694df96..02f2d3a 100644 --- a/source/behavioral/visitor.swift +++ b/source/behavioral/visitor.swift @@ -10,37 +10,48 @@ protocol PlanetVisitor { func visit(planet: PlanetAlderaan) func visit(planet: PlanetCoruscant) func visit(planet: PlanetTatooine) + func visit(planet: PlanetJedah) } protocol Planet { func accept(visitor: PlanetVisitor) } +class PlanetJedah: Planet { + func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) } +} + class PlanetAlderaan: Planet { - func accept(visitor: PlanetVisitor) { visitor.visit(self) } + func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) } } + class PlanetCoruscant: Planet { - func accept(visitor: PlanetVisitor) { visitor.visit(self) } + func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) } } + class PlanetTatooine: Planet { - func accept(visitor: PlanetVisitor) { visitor.visit(self) } + func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) } } + + class NameVisitor: PlanetVisitor { var name = "" func visit(planet: PlanetAlderaan) { name = "Alderaan" } func visit(planet: PlanetCoruscant) { name = "Coruscant" } func visit(planet: PlanetTatooine) { name = "Tatooine" } + func visit(planet: PlanetJedah) { name = "Jedah" } } + /*: ### Usage */ -let planets: [Planet] = [PlanetAlderaan(), PlanetCoruscant(), PlanetTatooine()] +let planets: [Planet] = [PlanetAlderaan(), PlanetCoruscant(), PlanetTatooine(), PlanetJedah()] let names = planets.map { (planet: Planet) -> String in let visitor = NameVisitor() - planet.accept(visitor) + planet.accept(visitor: visitor) return visitor.name } diff --git a/source/creational/abstract_factory.swift b/source/creational/abstract_factory.swift index 985240b..f279ef7 100644 --- a/source/creational/abstract_factory.swift +++ b/source/creational/abstract_factory.swift @@ -20,24 +20,24 @@ typealias NumberFactory = (String) -> Decimal // Number implementations with factory methods -struct NextStepNumber : Decimal { - private var nextStepNumber : NSNumber +struct NextStepNumber: Decimal { + private var nextStepNumber: NSNumber func stringValue() -> String { return nextStepNumber.stringValue } // factory - static func make(string : String) -> Decimal { - return NextStepNumber(nextStepNumber:NSNumber(longLong:(string as NSString).longLongValue)) + static func make(string: String) -> Decimal { + return NextStepNumber(nextStepNumber: NSNumber(value: (string as NSString).longLongValue)) } } struct SwiftNumber : Decimal { - private var swiftInt : Int + private var swiftInt: Int func stringValue() -> String { return "\(swiftInt)" } // factory - static func make(string : String) -> Decimal { + static func make(string: String) -> Decimal { return SwiftNumber(swiftInt:(string as NSString).integerValue) } } @@ -45,15 +45,15 @@ struct SwiftNumber : Decimal { Abstract factory */ enum NumberType { - case NextStep, Swift + case nextStep, swift } enum NumberHelper { - static func factoryFor(type : NumberType) -> NumberFactory { + static func factory(for type: NumberType) -> NumberFactory { switch type { - case .NextStep: + case .nextStep: return NextStepNumber.make - case .Swift: + case .swift: return SwiftNumber.make } } @@ -61,10 +61,10 @@ enum NumberHelper { /*: ### Usage */ -let factoryOne = NumberHelper.factoryFor(.NextStep) +let factoryOne = NumberHelper.factory(for: .nextStep) let numberOne = factoryOne("1") numberOne.stringValue() -let factoryTwo = NumberHelper.factoryFor(.Swift) +let factoryTwo = NumberHelper.factory(for: .swift) let numberTwo = factoryTwo("2") numberTwo.stringValue() diff --git a/source/creational/builder.swift b/source/creational/builder.swift index 65bfc87..7bb27f2 100644 --- a/source/creational/builder.swift +++ b/source/creational/builder.swift @@ -28,7 +28,7 @@ struct DeathStar : CustomStringConvertible { init?(builder: DeathStarBuilder) { - if let x = builder.x, y = builder.y, z = builder.z { + if let x = builder.x, let y = builder.y, let z = builder.z { self.x = x self.y = y self.z = z diff --git a/source/creational/factory.swift b/source/creational/factory.swift index 94051d1..cc04387 100644 --- a/source/creational/factory.swift +++ b/source/creational/factory.swift @@ -32,16 +32,16 @@ class UnitedStatesDolar : Currency { } enum Country { - case UnitedStates, Spain, UK, Greece + case unitedStates, spain, uk, greece } enum CurrencyFactory { - static func currencyForCountry(country:Country) -> Currency? { + static func currency(for country:Country) -> Currency? { switch country { - case .Spain, .Greece : + case .spain, .greece : return Euro() - case .UnitedStates : + case .unitedStates : return UnitedStatesDolar() default: return nil @@ -54,7 +54,7 @@ enum CurrencyFactory { */ let noCurrencyCode = "No Currency Code Available" -CurrencyFactory.currencyForCountry(.Greece)?.code() ?? noCurrencyCode -CurrencyFactory.currencyForCountry(.Spain)?.code() ?? noCurrencyCode -CurrencyFactory.currencyForCountry(.UnitedStates)?.code() ?? noCurrencyCode -CurrencyFactory.currencyForCountry(.UK)?.code() ?? noCurrencyCode +CurrencyFactory.currency(for: .greece)?.code() ?? noCurrencyCode +CurrencyFactory.currency(for: .spain)?.code() ?? noCurrencyCode +CurrencyFactory.currency(for: .unitedStates)?.code() ?? noCurrencyCode +CurrencyFactory.currency(for: .uk)?.code() ?? noCurrencyCode diff --git a/source/header.swift b/source/header.swift index 9f1daab..bfcab55 100644 --- a/source/header.swift +++ b/source/header.swift @@ -1,7 +1,7 @@ Design Patterns implemented in Swift 3.0 ======================================== -A short cheat-sheet with Xcode 8.0 Playground ([Design-Patterns.playground.zip](https://raw.githubusercontent.com/ochococo/Design-Patterns-In-Swift/master/Design-Patterns.playground.zip)). +A short cheat-sheet with Xcode 8.2 Playground ([Design-Patterns.playground.zip](https://raw.githubusercontent.com/ochococo/Design-Patterns-In-Swift/master/Design-Patterns.playground.zip)). 👷 Project maintained by: [@nsmeme](http://twitter.com/nsmeme) (Oktawian Chojnacki) diff --git a/source/structural/adapter.swift b/source/structural/adapter.swift index 5e21a7d..bc8efa6 100644 --- a/source/structural/adapter.swift +++ b/source/structural/adapter.swift @@ -29,11 +29,11 @@ struct OldDeathStarSuperlaserTarget : OlderDeathStarSuperLaserAiming { private let target : DeathStarSuperlaserTarget var angleV:NSNumber { - return NSNumber(double: target.angleVertical) + return NSNumber(value: target.angleVertical) } var angleH:NSNumber { - return NSNumber(double: target.angleHorizontal) + return NSNumber(value: target.angleHorizontal) } init(_ target:DeathStarSuperlaserTarget) { diff --git a/source/structural/composite.swift b/source/structural/composite.swift index 1c5f134..4c5662d 100644 --- a/source/structural/composite.swift +++ b/source/structural/composite.swift @@ -15,13 +15,13 @@ protocol Shape { /*: Leafs */ -class Square : Shape { +final class Square : Shape { func draw(fillColor: String) { print("Drawing a Square with color \(fillColor)") } } -class Circle : Shape { +final class Circle : Shape { func draw(fillColor: String) { print("Drawing a circle with color \(fillColor)") } @@ -30,16 +30,16 @@ class Circle : Shape { /*: Composite */ -class Whiteboard : Shape { +final class Whiteboard : Shape { lazy var shapes = [Shape]() init(_ shapes:Shape...) { self.shapes = shapes } - func draw(fillColor:String) { + func draw(fillColor: String) { for shape in self.shapes { - shape.draw(fillColor) + shape.draw(fillColor: fillColor) } } } diff --git a/source/structural/decorator.swift b/source/structural/decorator.swift index 413a191..29acf49 100644 --- a/source/structural/decorator.swift +++ b/source/structural/decorator.swift @@ -24,7 +24,7 @@ class SimpleCoffee: Coffee { class CoffeeDecorator: Coffee { private let decoratedCoffee: Coffee - private let ingredientSeparator: String = ", " + fileprivate let ingredientSeparator: String = ", " required init(decoratedCoffee: Coffee) { self.decoratedCoffee = decoratedCoffee @@ -39,7 +39,7 @@ class CoffeeDecorator: Coffee { } } -class Milk: CoffeeDecorator { +final class Milk: CoffeeDecorator { required init(decoratedCoffee: Coffee) { super.init(decoratedCoffee: decoratedCoffee) } @@ -53,7 +53,7 @@ class Milk: CoffeeDecorator { } } -class WhipCoffee: CoffeeDecorator { +final class WhipCoffee: CoffeeDecorator { required init(decoratedCoffee: Coffee) { super.init(decoratedCoffee: decoratedCoffee) } diff --git a/source/structural/facade.swift b/source/structural/facade.swift index 25787f6..b873dd0 100644 --- a/source/structural/facade.swift +++ b/source/structural/facade.swift @@ -8,21 +8,20 @@ The facade pattern is used to define a simplified interface to a more complex su */ enum Eternal { - static func setObject(value: AnyObject!, forKey defaultName: String!) { - let defaults:NSUserDefaults = NSUserDefaults.standardUserDefaults() - defaults.setObject(value, forKey:defaultName) + static func set(_ object: Any, forKey defaultName: String) { + let defaults: UserDefaults = UserDefaults.standard + defaults.set(object, forKey:defaultName) defaults.synchronize() } - static func objectForKey(defaultName: String!) -> AnyObject! { - let defaults:NSUserDefaults = NSUserDefaults.standardUserDefaults() - - return defaults.objectForKey(defaultName) + static func object(forKey key: String) -> AnyObject! { + let defaults: UserDefaults = UserDefaults.standard + return defaults.object(forKey: key) as AnyObject! } } /*: ### Usage */ -Eternal.setObject("Disconnect me. I’d rather be nothing", forKey:"Bishop") -Eternal.objectForKey("Bishop") +Eternal.set("Disconnect me. I’d rather be nothing", forKey:"Bishop") +Eternal.object(forKey: "Bishop") diff --git a/source/structural/flyweight.swift b/source/structural/flyweight.swift index f893619..02e4efd 100644 --- a/source/structural/flyweight.swift +++ b/source/structural/flyweight.swift @@ -4,42 +4,43 @@ The flyweight pattern is used to minimize memory usage or computational expenses ### Example */ // Instances of CoffeeFlavour will be the Flyweights -class CoffeeFlavor : Printable { - var flavor: String +final class SpecialityCoffee: CustomStringConvertible { + var origin: String var description: String { get { - return flavor + return origin } } - init(flavor: String) { - self.flavor = flavor + init(origin: String) { + self.origin = origin } } // Menu acts as a factory and cache for CoffeeFlavour flyweight objects -class Menu { - private var flavors: [String: CoffeeFlavor] = [:] +final class Menu { + private var coffeeAvailable: [String: SpecialityCoffee] = [:] - func lookup(flavor: String) -> CoffeeFlavor { - if flavors.indexForKey(flavor) == nil { - flavors[flavor] = CoffeeFlavor(flavor: flavor) + func lookup(origin: String) -> SpecialityCoffee? { + if coffeeAvailable.index(forKey: origin) == nil { + coffeeAvailable[origin] = SpecialityCoffee(origin: origin) } - return flavors[flavor]! + + return coffeeAvailable[origin] } } -class CoffeeShop { - private var orders: [Int: CoffeeFlavor] = [:] +final class CoffeeShop { + private var orders: [Int: SpecialityCoffee] = [:] private var menu = Menu() - func takeOrder(#flavor: String, table: Int) { - orders[table] = menu.lookup(flavor) + func takeOrder(origin: String, table: Int) { + orders[table] = menu.lookup(origin: origin) } func serve() { - for (table, flavor) in orders { - println("Serving \(flavor) to table \(table)") + for (table, origin) in orders { + print("Serving \(origin) to table \(table)") } } } @@ -48,17 +49,7 @@ class CoffeeShop { */ let coffeeShop = CoffeeShop() -coffeeShop.takeOrder(flavor: "Cappuccino", table: 1) -coffeeShop.takeOrder(flavor: "Frappe", table: 3); -coffeeShop.takeOrder(flavor: "Espresso", table: 2); -coffeeShop.takeOrder(flavor: "Frappe", table: 15); -coffeeShop.takeOrder(flavor: "Cappuccino", table: 10); -coffeeShop.takeOrder(flavor: "Frappe", table: 8); -coffeeShop.takeOrder(flavor: "Espresso", table: 7); -coffeeShop.takeOrder(flavor: "Cappuccino", table: 4); -coffeeShop.takeOrder(flavor: "Espresso", table: 9); -coffeeShop.takeOrder(flavor: "Frappe", table: 12); -coffeeShop.takeOrder(flavor: "Cappuccino", table: 13); -coffeeShop.takeOrder(flavor: "Espresso", table: 5); +coffeeShop.takeOrder(origin: "Yirgacheffe, Ethiopia", table: 1) +coffeeShop.takeOrder(origin: "Buziraguhindwa, Burundi", table: 3) coffeeShop.serve() diff --git a/source/structural/protection_proxy.swift b/source/structural/protection_proxy.swift index d20c1c4..bde142d 100644 --- a/source/structural/protection_proxy.swift +++ b/source/structural/protection_proxy.swift @@ -8,11 +8,11 @@ Protection proxy is restricting access. ### Example */ protocol DoorOperator { - func openDoors(doors: String) -> String + func open(doors: String) -> String } class HAL9000 : DoorOperator { - func openDoors(doors: String) -> String { + func open(doors: String) -> String { return ("HAL9000: Affirmative, Dave. I read you. Opened \(doors).") } } @@ -20,9 +20,9 @@ class HAL9000 : DoorOperator { class CurrentComputer : DoorOperator { private var computer: HAL9000! - func authenticateWithPassword(pass: String) -> Bool { + func authenticate(password: String) -> Bool { - guard pass == "pass" else { + guard password == "pass" else { return false; } @@ -31,22 +31,22 @@ class CurrentComputer : DoorOperator { return true } - func openDoors(doors: String) -> String { + func open(doors: String) -> String { guard computer != nil else { return "Access Denied. I'm afraid I can't do that." } - return computer.openDoors(doors) + return computer.open(doors: doors) } } /*: ### Usage */ let computer = CurrentComputer() -let doors = "Pod Bay Doors" +let podBay = "Pod Bay Doors" -computer.openDoors(doors) +computer.open(doors: podBay) -computer.authenticateWithPassword("pass") -computer.openDoors(doors) +computer.authenticate(password: "pass") +computer.open(doors: podBay) From 8ee211871ff67e9cc6076a5a8993e9386f21bd3c Mon Sep 17 00:00:00 2001 From: Oktawian Chojnacki Date: Tue, 27 Dec 2016 08:02:53 +0100 Subject: [PATCH 05/66] Fix README.md. --- README.md | 8 -------- 1 file changed, 8 deletions(-) diff --git a/README.md b/README.md index e340b5f..820e4f0 100644 --- a/README.md +++ b/README.md @@ -13,14 +13,6 @@ A short cheat-sheet with Xcode 8.2 Playground ([Design-Patterns.playground.zip]( * [Creational](#creational) * [Structural](#structural) - -```swift - - Behavioral | - [Creational](Creational) | - [Structural](Structural) -``` - Behavioral ========== From 62c1c3fbfba5d4dcb205181eb14d2735104c0a32 Mon Sep 17 00:00:00 2001 From: Oktawian Chojnacki Date: Tue, 27 Dec 2016 08:12:45 +0100 Subject: [PATCH 06/66] Jedah is a moon... Who knew? --- Design-Patterns.playground.zip | Bin 144531 -> 144523 bytes .../Contents.swift | 8 ++++---- README.md | 8 ++++---- source/behavioral/visitor.swift | 8 ++++---- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Design-Patterns.playground.zip b/Design-Patterns.playground.zip index 479877bdaa3f07f280874a636a221cc39a6638e4..619cdcdac5ea6cb27b6d1e0a08eab00cbf50eeda 100644 GIT binary patch delta 10784 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 String in let visitor = NameVisitor() diff --git a/README.md b/README.md index 820e4f0..864acc9 100644 --- a/README.md +++ b/README.md @@ -691,14 +691,14 @@ protocol PlanetVisitor { func visit(planet: PlanetAlderaan) func visit(planet: PlanetCoruscant) func visit(planet: PlanetTatooine) - func visit(planet: PlanetJedah) + func visit(planet: MoonJedah) } protocol Planet { func accept(visitor: PlanetVisitor) } -class PlanetJedah: Planet { +class MoonJedah: Planet { func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) } } @@ -722,7 +722,7 @@ class NameVisitor: PlanetVisitor { func visit(planet: PlanetAlderaan) { name = "Alderaan" } func visit(planet: PlanetCoruscant) { name = "Coruscant" } func visit(planet: PlanetTatooine) { name = "Tatooine" } - func visit(planet: PlanetJedah) { name = "Jedah" } + func visit(planet: MoonJedah) { name = "Jedah" } } ``` @@ -731,7 +731,7 @@ class NameVisitor: PlanetVisitor { ```swift -let planets: [Planet] = [PlanetAlderaan(), PlanetCoruscant(), PlanetTatooine(), PlanetJedah()] +let planets: [Planet] = [PlanetAlderaan(), PlanetCoruscant(), PlanetTatooine(), MoonJedah()] let names = planets.map { (planet: Planet) -> String in let visitor = NameVisitor() diff --git a/source/behavioral/visitor.swift b/source/behavioral/visitor.swift index 02f2d3a..fdae2eb 100644 --- a/source/behavioral/visitor.swift +++ b/source/behavioral/visitor.swift @@ -10,14 +10,14 @@ protocol PlanetVisitor { func visit(planet: PlanetAlderaan) func visit(planet: PlanetCoruscant) func visit(planet: PlanetTatooine) - func visit(planet: PlanetJedah) + func visit(planet: MoonJedah) } protocol Planet { func accept(visitor: PlanetVisitor) } -class PlanetJedah: Planet { +class MoonJedah: Planet { func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) } } @@ -41,13 +41,13 @@ class NameVisitor: PlanetVisitor { func visit(planet: PlanetAlderaan) { name = "Alderaan" } func visit(planet: PlanetCoruscant) { name = "Coruscant" } func visit(planet: PlanetTatooine) { name = "Tatooine" } - func visit(planet: PlanetJedah) { name = "Jedah" } + func visit(planet: MoonJedah) { name = "Jedah" } } /*: ### Usage */ -let planets: [Planet] = [PlanetAlderaan(), PlanetCoruscant(), PlanetTatooine(), PlanetJedah()] +let planets: [Planet] = [PlanetAlderaan(), PlanetCoruscant(), PlanetTatooine(), MoonJedah()] let names = planets.map { (planet: Planet) -> String in let visitor = NameVisitor() From 93430e4da668423ff7b89203deff55285d0d88ea Mon Sep 17 00:00:00 2001 From: David Orriss Jr Date: Sat, 17 Jun 2017 00:54:06 -0700 Subject: [PATCH 07/66] Fixed compile error and spelling mistake --- source/structural/composite.swift | 10 +++++----- source/structural/virtual_proxy.swift | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/source/structural/composite.swift b/source/structural/composite.swift index 4c5662d..fea9bd5 100644 --- a/source/structural/composite.swift +++ b/source/structural/composite.swift @@ -12,9 +12,9 @@ Component protocol Shape { func draw(fillColor: String) } -/*: +/*: Leafs -*/ +*/ final class Square : Shape { func draw(fillColor: String) { print("Drawing a Square with color \(fillColor)") @@ -32,11 +32,11 @@ Composite */ final class Whiteboard : Shape { lazy var shapes = [Shape]() - + init(_ shapes:Shape...) { self.shapes = shapes } - + func draw(fillColor: String) { for shape in self.shapes { shape.draw(fillColor: fillColor) @@ -47,4 +47,4 @@ final class Whiteboard : Shape { ### Usage: */ var whiteboard = Whiteboard(Circle(), Square()) -whiteboard.draw("Red") +whiteboard.draw(fillColor: "Red") diff --git a/source/structural/virtual_proxy.swift b/source/structural/virtual_proxy.swift index ca11ef8..9d59035 100644 --- a/source/structural/virtual_proxy.swift +++ b/source/structural/virtual_proxy.swift @@ -2,7 +2,7 @@ 🍬 Virtual Proxy ---------------- -The proxy pattern is used to provide a surrogate or placeholder object, which references an underlying object. +The proxy pattern is used to provide a surrogate or placeholder object, which references an underlying object. Virtual proxy is used for loading object on demand. ### Example @@ -13,7 +13,7 @@ protocol HEVSuitMedicalAid { class HEVSuit : HEVSuitMedicalAid { func administerMorphine() -> String { - return "Morphine aministered." + return "Morphine administered." } } From 114dc8a4fd89e93153417f6348aebf480cb6d0d0 Mon Sep 17 00:00:00 2001 From: David Orriss Jr Date: Sat, 17 Jun 2017 09:39:53 -0700 Subject: [PATCH 08/66] new example for the Template Pattern --- source/behavioral/template.swift | 70 ++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 source/behavioral/template.swift diff --git a/source/behavioral/template.swift b/source/behavioral/template.swift new file mode 100644 index 0000000..8a0188f --- /dev/null +++ b/source/behavioral/template.swift @@ -0,0 +1,70 @@ +/*: +🍪 Template +----------- + +The Template Pattern is used when two or more implementations of an +algorithm exist. The template is defined and then built upon with further +variations. Use this method when most (or all) subclasses need to implement +the same behavior. Traditionally, this would be accomplished with abstract +classes (as in Java). However in Swift, because abstract classes don't yet +exist, we need to accomplish the behavior using interface delegation. + + +### Example +*/ + +protocol ICodeGenerator { + func crossCompile() +} + +protocol IGeneratorPhases { + func collectSource() + func crossCompile() +} + +class CodeGenerator : ICodeGenerator{ + var delegate: IGeneratorPhases + + init(delegate: IGeneratorPhases) { + self.delegate = delegate + } + + + //Template method + final func crossCompile() { + delegate.collectSource() + delegate.crossCompile() + } +} + +class HTMLGeneratorPhases : IGeneratorPhases { + func collectSource() { + print("HTMLGeneratorPhases collectSource() executed") + } + + func crossCompile() { + print("HTMLGeneratorPhases crossCompile() executed") + } +} + +class JSONGeneratorPhases : IGeneratorPhases { + func collectSource() { + print("JSONGeneratorPhases collectSource() executed") + } + + func crossCompile() { + print("JSONGeneratorPhases crossCompile() executed") + } +} + + + +/*: +### Usage +*/ + +let htmlGen : ICodeGenerator = CodeGenerator(delegate: HTMLGeneratorPhases()) +let jsonGen: ICodeGenerator = CodeGenerator(delegate: JSONGeneratorPhases()) + +htmlGen.crossCompile() +jsonGen.crossCompile() From fad0d2bb31d6b14e9f338389f3277957f48aa102 Mon Sep 17 00:00:00 2001 From: David Orriss Jr Date: Sat, 17 Jun 2017 09:46:24 -0700 Subject: [PATCH 09/66] new example for the Template Pattern --- Design-Patterns.playground.zip | Bin 144523 -> 151298 bytes .../Contents.swift | 71 +++++++++ .../Contents.swift | 14 +- README.md | 138 +++++++++++++++++- source/behavioral/template.swift | 5 +- 5 files changed, 212 insertions(+), 16 deletions(-) diff --git a/Design-Patterns.playground.zip b/Design-Patterns.playground.zip index 619cdcdac5ea6cb27b6d1e0a08eab00cbf50eeda..7510e583ebaf02988949596229e4133cdfcfa55c 100644 GIT binary patch delta 14814 zcmZv@b9kiDvo#vqoY41s){&<@y~)qQj!ISfCKsaVu75Ii9=$C_&fSZHcEn)FrYd^&&d2+{I4$- zU~M`mJKkRs#vd2VKaxz!C85cmS;(J{%s&7yh!Hdh;xD-vi3yY+^>4`kituj`{EOlQ zGSY&<|J%U-#A>#;1N8#?w+G;bJt*>Up0$fzxzgq(I*&P&lN1`575O!tj_1bPy0D zDIjPdC>0Pn02Cis6$6S4;2U#VmvXZBO>6Cibh5}Htb(o+!Yjv2ZT&;TL|G*z@gT=Y zP7QovqY*->)4gVa>~t>yxyfS5BBWpQazhf3AlRF#jf~-YLg++CFrI=UtftXLL;FoV zrN1A?i&EoFqb%Oy>@r`}{raN=qa(R&d*!~xJ8Sv(SetEp+gHaHfOnQyNQ}911Ral~ zpz__FcrQ(331rIQflkg{95-}~-Jh24zQJch9L5zm8ci8P5%WB`Dp4(PA6rlgAeGIl#yijh`pdv`fQmf`QXXc}>u#IE|Ddz5(L%_EPX2kN2D7 z_SL=rduGXESqZ}0Oz&hib(;=s@-$x~i1_nu1bK%?=g3PoPoGCgCV(8NbA zs=B^>>h>s{vaJRhp;K2-l5fzS_5??rLG5$0WAd*-k;Iy4TgcP+FqY`N>aLgY_XqH) zrPP$%8hBXq;rK}KBzX1EbG%g82j=iEZ>D)rv)W|lXX46pwA+F2wZ9GV?weklP>8HE z_-w8-tl8>f0rxF~tmmXDP!i6$%wCxKKG%Pf+gV);(-?TxcDr3#IteiG1mLKdLOJa#RUt$ zY!J*Q8p#RXL6PKS5?_09!@|scDS`ThmwD@-!7`avdpRuD|J5hEQ(j^+kLe`m(nt5Y zP-xiOeT3THml#fq1_6rOI$XqoG6D~wmK!3j5a1gUPe4@LZ4`5zP4zT&J)`_~q#XDv z8gV*r%YT0zcUc11Z9f(fp%GE7#D%UW`e82kU;)n0zg9J6c$2`N5SEv<#Q^YqMhZ6} zf{e=)E9td}8dq7*aTF8ioCL*rTfuGgNYUXf`lf2p`tqozO9KnV>Clmc?L4t%JXE}GAQqdLx=sWeb$rM24A*knV33XMHu{u z7)z$mkpsNMy=k*pk5Vj|-s^A=HV%D(MYoL%i*UjZwZszsCGEp>4)A##;N%L8)M~PC zed=)R6~SiDB+X#VTdWWg^(~KkC)bg=0U)vS`0h**V00Ku-DeOAbqw?&l4%|YaSc1h zYEE6mK%c9Sb~IVy0tWbipu|^Z6#GBmc7gFrkN7wyi$&<&#vg)BYlebeY3K1MMyF1} znA`hy2vzI^NTuO2jqnYdHewlK!Q};k@ap%7LRHI{a>b4bH))kas6-sfBuV_-1;mVa z;p~}A=^ItdDxcizV7N`v`GRul!P%Fmrs7x;S&$bgJK8>78bE=6 zU~of*Z`n9y#jwR^Sd^iC3W||vJci!9)&l|FE-rzjYQ%2Rm{R*;xvT1@QYRp2ia4U7 z9O0M1B{FaouOj0EtA}>ypTC$!0pF5-S9HBt-uUc4KbaI?5ObIU1X&b&K&uR{3M+%l z^vmyXwgfnfm^|}Upa2Qc<;tc}XCj4&>V&@=*~+dQgiWmv2h&_Xqm-i@T|VEwrTB)T z;bXty1)a#RL_=p1wt0?|(ZHDH`Fg6hS43jR1~7U>Lj~CrAjTVn-!!k<1B@+tesDrv zKS4XVf;1WXuRFIBGYF&v1kEnlLtfy-X zR`KiruK>3FSV1(s{#woL=8WIYw2O=N`hK=5i^p2{J?*~5H)VU&M0+{Tp6uk2YyU+v zfDgkxV4E9DRJ>!iaPL;G0l*^PiRN=O5-Sx!N$HtMixk~KvtQ61D^OYkk0wXG`t1a+Hng&50kSp0Zok(&uxEb8~ zUA3*Z!$zDORx&(Q+{^?3-lm8wpeUkbh({vk&H%~nhSKJ|QoQfZ2oYw(?F=5y&tk$h zHM*V;0UjTKH=r+C-g^6)S{6c1;qi+8sT9xC-awz#nx=__s3gMw;fa=Nh2p_9N8s8f zGGhy-diq6ZL`XAOjGC$~LHbwptDx+0j`v%|Gk+fOT!39#dfYSzz4$8ma**{R4nsTt zuR=cA6qD_T2KA$^907N+PxOGPDr-Z8$I8sT%t^3cYRNVB_2-GWX4^it5eU%saE+s4 zZ3PTu#EBFMEyB(<&}C7@ZTsd-qONKFe3(_DgWoBjw|)<>+BFInTDy^*wVI9I;zx17 zUEcd}*8%cT>#DIpwSzh^P5Mn?LbT^D!$t-sa|+q(9jrDO99$oQ2sw_Y z&Zs8L+Zq#AP_}w7L2b}j;`1bQzu!wXR(@N(VI$yOPAxu`w%FA+W&TzjXYy#C0t-oT z6Z?D7anA9!VHw&i8YdK5)})c2+7^u0z`60@IS3#U!1y{Yzao*uX`G`m)<785?!*lx zQ(7Vw?j2iA=2Hu@q2fUHUq4igbvQrO;!Peb#$#o`X+Sc4o z5&{77HAcPbzA-Rbe{Cr^n)*Z>^Cy%+oWyi`7ud5#?-~*ldu2t3Ah9SNy?6BT3eGTv zykqJVktm1yN$<{WfI*zxm8`mpL!N~plop!vHK2JNAAX(%n?W{@)ziyCnd2Z51&sQe zXq{En)E$9&r~d9afq^zNbDO>ZFfr%aNfu!3uK$a|9Xpciqck8D)C}D8M`K2Ng6SQV z1TSmIBblzhtB;e-yV6iOkA+~$uPhCh|7oK=ZRj#KO(GTJqTb{ z+%Ouh_qkeG%XN?O?F!E2Ph4y#GdJjv!>@< zqeA>3_kNi4qFK3<0&ptHEbF~$?|B`J@z)0ykE5HJm+Jq>8{>w?k8PQKKow7@zfF?* zzDa$&$}zO(a^z=i^%mgvh2%CHZ2(YCU~I*ytSVQv>;s$M4Yv7D8KFu)vb!)J9+!<-0r8@lr%k;K{C@(cUvk5lmTmS?lV0`q`4y;`+xgef-;41iPAihU)QRHqVxq zNx?l1jTs5coBNi`87wQnizeW~6Din>7EC;ig)Dd6&mwiz{VUi3_5@$T0vv&YUm;3I z-(<*U<&2Gt-VRSdl|{xX}#XW|K)FwPtL9PgUwFq2MN_jc7?BXo;ED8if-A^ui3SppH z#?_=Rs0Wv>ecQUS8#e&ZxT4ozLZp{_LVidVrTCWXJTm)&&hh$%ACT26Uyw$l^F}s z^`1N@YWXH?`Fd{ZY{S9n=tFXQw>r)#!k|0xhS+gxkaF$eH-)@)M8Z=}lz6N z6zdttglZBW^;vgV8lPEW$bHM+jZy7iL~+IGd_I+IKJ$C=HPQh-k!74c-ttd|5=rOY zji8M6-^AMV5!*DjtlyBv8=P}R?k;CD&-ccgMpxOvJ=FkV$Qmk|^Dpd2n|xd!7qo;v ztyl1c&ILa*l((N+d1vjWoQ5}rEWqX8zt%QNer`;yyoMIH4nXa^TW%}cf@*&+N|tT& z31gVpUX|}|C%d3s1l~MRUfRC~efrTtUnZ{^?R-m(GaOUeIzN1gS1c7DPH=*1ftDFm&Nd z6@wsL%fLeueuF}ItMz#57l*?Vt&GYr8m6X^Iv3L zMwOlL2uAdwQnJVJL64o27Cszlm@PHh;{!)0GBxYsETLBsN`_;?=Htt8)_!})iNk?F zJnH~Vb6<*-gWS`xpM24^f5BVV^Zmg-zE@VZ^5u4fF5R%dmvDI%4>!6WhF>*ku>PGG z=ZVIH=DvB#T~2P9vusr5Oyi2Y_aU}IgPPlE@UUe_nn0WMjs%*EUg}#Zm~a;j$3X+% z){U+}*ve&ZMh#aDJV#@8w-{C?uc-p253DGF$7Gkjr3Czq2VAREjX|X=Q?52_Tg(P0 z^3PLWReqiGyb!2n>K-Sa-E!6{?_H&G9YxK9jqSn^n#pvQ^qWc{LBaa5Pu{(LhdMw| zeyegOTQY{~^=buw)536Zw}gL!8SHoA4xz_X`vnxPfhb4LlXQ?r!(^Hd5n&ra?vfTD zLWGc!Sn04VTmn19Wd`!-WZ+r-mSSjOaIC8+#Q$9R;|fa%#tabuPH2hI!rUUe=Y7=f z47HruvSrZabDuhhnEMvF12yy6(K5qid~6SY$_MTez%SI=@Yrmz4;rM(25t)|QM*R; zA$7Mf1$9KxHhntLEhm`vJaW&3p@>^)>8JqG(Yka79T`LP2f*PcQJzT+0`%?%d+qgKbh%&Qep#cG~i;myr5 zQPs(z@bM_jo4Og@5bZAy8|AN3l{ka0PjyOTgutz#*z}OJkF>?bF_d6)ULS{Oi-||$ zIJrcut!Uj{7Z>#XLyOUUr@CYm^zN+1o~_xfUVuqFjvcoR7v=_?^;<=bLl+pvYd3J( zA9Un@WdaSOK%s!$^kDe^(t!|v(}B&80if{k5PW}9j=+D}!Yii#oh{^v3vow>2LZvO z_)oUbn+c2tu%JB}y*`A~^{ASt1N|dL@+>ZaSPDMh5DSr943F;y!jJq5yQ%9BGbt>6 z^)rnz)L7zT5CsJR@?w1NQQo~+&TI5N)SGwp^-;no+kS}y;#%#`uFt_0+erh$2+VJ? zg&uF7DuRkDL=vn#0yF-)r7ApC*<-uT<+sxZLSH5x00;R)Q~f9QY;B*^W)k#g!8W~O zZHc8QIz?mN<}?skuw=lmV=av$#lfhykD2<8V-TERiVMg4$)i#Q8VpT2qg<>kqsF}) zKgTMJW4V*Qzzvfs`%Arj9*o;g{s$+rYEw$mQSd@w zH5IK5p#IsGayG}6DgRr&&gB%mc5!~^3XBuA-O95BgYEOK+`iQwgd^7LrC|3*IDt4H z`0SCwJtuCbum5^Cs04rQVsUm@p$fL2}_Eba>rt=b*l532a za5uWV)A`-|N1qD##TsbTn7yzhMY2gYb^-OkN{B3eD^-TCY>SV^6X&U*m z0QIU#{f6ha@VS);c*Pf5MY9TRPlSfu0f$=(@LhKnVjVC%BWE?VlOXQW^$-jI-sviS zmoY+z!S4y<_6MbMW9-d+D?`aCyrt1?o0XlKrA3fVRF!W$+P7TTxBl+BhgP|!oYY-- z3#;SwZIhMR*s-^nW%n7{TDvtpw$B0afL+#pAOkyY5%0QPn}KO;SbtJ^xhvH2yQZ}f=2 z_R+*Cx)GFu%{4=b={Iju!CO_uipvwaP<-yO-73r=;9XC*3%&T&prS@viVO=x00WGu z`}oQX#&J31I7L|M;<}bePa+aGbG5X6mZZsJ%V*e_jTI4L+w=A%-lojzof{=pPG#$L zV&dY+)-vEDHr8a3M*ZsbQ0Cfn9^sS&(Z3`$k8*63;juk%S;EgPj!na_%1YUptfexs z4L4D;!^N~6{X=KrW}L}DCA_;j0U{cGP+8eA-Y?C{U!kQgDaH0H(Q@PpMZ&PLZ*3Co zV#R7@&P{EX6dWL;WQOOw^qsKz#&7q?gXe-in10!WgcCcr$TPIhWsln~(Mt-gEM68> z8tBOt%_&2Zlz{cb>4Lbdsq7Bz>1que^EX&eif?|TXBv(xNvxWmXsqBR142Y$@n@yJ zF3Z48xVGelH^pSYJKOEyY8MBU1dIJfTb*z;-5J}8K;iBZ))r|hTw^(h4MnRFF@dG* zmF)@4Wf}k$qmETZQoIYz^o>|vN1wvve7!rTqANXVkn7FO?4`|W1f!V!$*MiVC7@h8 z`&~jpJ_XC~O6w|!1Pnfm8_-6raQJPH?PAhiu7W6}802o(UU+=MnZ&48lRe0aj6s() zLn`Xaho2Y>e=T09(#nFk;xJve{_p)l((Z=+@aMHkT8&@>T(L*lA8%>1xih`**Xx;( z!qesKm~8;dNf1so?_4+%>gY5!81hhh^a3y+PCfPmvz6s}N&vU*vc=8@XX*v^ zMKNEMkyplWcDSV;<<+J@?~RRvJHDC%~;AU3L767(G^A668@2)i13EU*5-bJQ0tl(4zEE4w7A?pB3}` z2kY|4Syyl72rvC-8{0Y91?{Pi*TY$tEo&g}r!;UpH|$g&eN?2@HamlHwU&LqWGb8m zix;>9j|eX7Yc=y%sr6Scwx?w`k?^VAHW9Q>-YG9oU}*|2%>YlJW%TR6^WMaUG;gb% z;dY3=v#o;p8y!tXBv)C}Hx#u8r>{-dmkA4+L-#UP6?&M6Y80$}Awq`4+l(F!+%-DQ z`)O|H{NBCx1Qd*l8jWp?3c&*^OE*6eG+C26<)n~Fk+8jKCg2t?I(x>j7o3PTiWMp6 z3qXm62X|Rm#{!5%gL%$;z@&c;f39UO<9tqW@>wICb*(VEhc=653ZRV;C>vD&3UaYh zHh=^3&F{4qyvU~|3uTyC)QY=XtB|T?=668kmAGpiVQx?h5zweTHg>;F0BNdqX;*Y! zv>!+g-1e}|z7a!^H|Y}QM)|VKDhky8z&_i2!$|}O1Oaf>sSGc)fqI9CRdb+$cDPjy zGW)tS-_hig_y(nOhcH7mcF0h3cUYkvPD7N7ta%`XB3?6=6>&Hbn+lh~$E<%-Spcs~ z*>d}W17Yb=LA~zIi9S)8#hCOFjrwJh^o5HZ&04Q(*=UnUu4GsUl&wLgQjGB5S$QLx z@koHQrvQ_>H+GC<*l;_M$5&W4wa!7W5&2u{L8I>xmzXK4tZ}#i&}gIe1%55!(SFSL znD_n`?%7JZ3#iN;y`d7l!8_bLjXoTwsg~ne`XYhTN#m{|TUZfCIm%qW7M0m%|S;x1<)7J|HUw7-y{d|Mm z)iY1B6hR3t4w&c0??YL{W3^6m%a@d{eDMIwM#+Zla(lOs4;fyaSt`{NwgFBl`=QT;u zREO!frSPcfkXU5&)>?%$XNU{UegA{8nh}r&TfZAFSb^xhT*ISXA^`Wof%~a&La`5H z_%K7QsbUr%Lz};m*#-T{1)ydBc0fHe6MR{}i|_S=+y+k2CPFD?((3wrtJ{3478<^} ze{MJ3?p3FnnZeY>^Zije!KN}9gW4rP=*Kawcy_ARiYX^;7-_|zh~;nVuZlPYm^=Wt zAIF3U?Eq2gDXg;wrckPm0;h|r$13d;#iZFOrWFpTpIhlOxRj_!^6d~VSWh96F#uNw z2O*;NF8JJ!6n-3Ra^_t+toW|B5q5l^UrY14$78MoO*F_~Qf4Y|Xcd3rve{3EX9OoP z?`O6YLGL2LtuUk$IvJd}mdDBPNv;88j$h+36A2sXsiouN76)E>PpzAD<@y^K3@5zTxwP0jIV-z z2*`Z-X30RtMYDG-nX-`hYD*YdT{)L!G>tLOd+%LXz#=`ofc|;Ts5-;EHQNaI<&4Sf zSpdRh^6M5fi}2?v*T!$>%c0|YwQ#QiKrMW!U9<$N9=p$38Z*sc=}C}@xE+ZGUl~d2 zYZ}myqqXQK-%kg}EZJ9xSGAE{GWV{y7rs1UjMHeJJeS}$+F*N7c+!!nOX2U^2GtNY zhNN;{k3S*jLbzSL)#&ZpgB-Ex&nN2QDw~3ZVA@3T`R)}f4?c5c*sP#MN0y35$|~o7 z*VN_ALg63W3I3J)ftU1PxWEg4P!iyu!!tgxh7k-MC=dXu)0~qII>?Lj|5g#?{W*;P zZ>eAXuhcKZYGQ9{=3;5@YGLWZ;BMmTZ02NY_LAU+hvprYD|75#nGrH5r?I_tfk;L!%&x4);zn6dlf=PIVVgkL;}l}14;1i?*q^V)`}$deJIs1kj=Yi9YqD6 zvhv0MNX_o7nhXupkp$On^a!~IpAG<3F+_+AvSK1I?~zM^{39~8#zKoLAy6p6S@iHx z2eAI8yYfdCv-CIDg7V=)P8J2x+5V{oi`_fu09oPh>Oi1}%-JLFK(!9}qu;Fs`XY$H zfoL6Bu^(XI4wV(O)#H4{*8x-AXLH4K76R^ovgsSMZSq9+6Dj03{1e_A!3XG8UpFjC z;?W2bOGbu}L_)18SgO>l6jCh;RjT|!ESQQ^_y~@vKq>h`LG*kA#em`@*_gC%LoAXL z=rK8VJcGX}W@~%}#p!62DR^txx*SKs_gPW%xJtm@_qt3zAwu%@5yBg`71@V4>`_@$ zL63x=QUatz34#gTvE6aiqo1+%CCMixS-6%g1QH>0$}VgKid55KE@+uD#WVP6vX%4F zhqJ~!*~xQoIi@Ly+Tk1$;@_2rjlPLC)(c{k*mrz`J_ z+7bW)B0pv%k4^3z+tLMuAE%3t4cf8^^X#WNk9F@Zxe!7gd%woQsp3HHl7O>ZL*V-%v+B4kM?$7FCFZ{dbSZh2 z?pdL347Gw6mp`y!1^J_X#efNoUo)_51Y*HfWyFKEa}Vo``)~)L$wqJ2!TRU7%ugvt~d~9IiL*S!c}!Zi0%YeFzd@ibT(wjKuT5e-A!>HbD-b! z{lUyE7-%K?1(QMmKu(S+l{ak1R(GjBCUTCMh52EQ>~+o&O$!r}Dtiqx`JRQ2lJ*qs^R)f+tV z$QJHco{bzqe9Ax_0;dI%)X@JS=N-V|3jDwAV zVfrRk(M6NF^_efenuHj>QU?t%NTE!bXkbgRK;xtRY_PDn+y}*h&=bo{iz8HzVGaKh zJ~-55F8=dt1&Pe8Z*%_Mp}8_HHMfAt8UH0#f(D96Y@-Kj(K$41ABtZS)F3a!N?W-q zq40L$<2&!e>=gp0(eZnK8PH5S1ywwI4EN1`*qs z65FJxPj5atnqvG5NM9lTHkxTSL%&suhW^F%ux@oAJ5w8Wm4CSryTULIS3UM3i@ZTZ zeaZ!vV+;qG5l>NEsMg>((=wglko2Q7$1vpsCU_+J4Cm83j&X^2q!huc8QNlh@b?zf z`dU7T`H7m;*Y2n*n`H<lkS`i=Gn+I!~(t>Wa741tXmgZJ*QJlTw))!mon>^D7zsw;6dh(e(@%Uhnd;4q9 z3H|gfC82p{f{J&n*0!15@!k5-$C3Gi>Kz%fqMyg1F^!eIQR{DJm3pub);&6nx$xt8 z;QV`I`<6+&8S5h1)nz`g%#E1)%HHWoon`4O>C6$W!#!v7%m_#O@2KeSAkqgZZr=oI ziBYKGL)Kc#SfLRC;a_c;90upC3>3#IXUa#*bSleuVVD^@!lZS#JBdU%C&&+r;v2y+Va#)^Rp zj0`zce;Eg)c4_f^XRb53N`F-fTF2E1jr&mN)Cz?vm;@OI^YRE<5ehsv?Fq_zjldOh zEy#N@3yu{#4$M+kc#g>mStVG-n$Zg}`tOkKV|jUnDUczuNEkHFRP}>}2YKwekgO(4 zg~?8pSoLRsHFYO2^YqaRwK&~$L)AIN6gw=uTX2rvGPJA>5@^=OW!IFauUhA0eB2O zDte(5TE96C7Cctm1Ua+dL$jnXTGriJe3=&yq8g<0oQ7TqY>)gDw;%sJa0jQf0se|B zYl8KFfK3a;_uKgqjBP%*8{Ya{CA}d^80jouRE(nT!0Pp(Q9c`VL6NUF2_fp9Zz{-d zn5%$1McbR|=RL0MsX?}aJzA#}hviX{FB+6@RBtxQ;_80n9z34Qz=y<$ZcPE`ZQkH3 zA}+8kbgi>fLF)xc<6_*3fqK;SAw>BzYIkdZfq{V?b&qGzt#x1CKuoZQUUZyUZqtET z9A9<|sUn)L=G4VeUiC;k)KzAv!tdKEgUwYlpn9zbSHWL)GP3SR^| zLpTK5=Q-&{!qKU7nsHEf8J3ReIfGN!5!lqQu*w-1xg<_@9@`HGdku#sLBm)UhSc9__W36p;zr}x!BfPbY>u|j}Fv(975Xa8HXI+Q8 zb}iDu1?7OK4V~{b(zvJDg2wAP;=1SA0m55r2^)a(1taQ=SCa0L4f;KfBl`=so9726 z(Wo$QaBJLpysrmsD`NW**r3kL>Zc8HNUFi?7`Qxw6JBe;?MevH zt>3l?dXkDY&w-ja`Q?xFLgJV-#Iq&pb~X99v%j$?(6KWdc!PrdtKXEWs;~St=!SYF zv!@4rPr3uG+8ALVVdwZ+vr^9R1?NVuFXeC)z6E#bs^eUWyL}_OPGL&WLa}cdI9l#V z-xa)ch0g)-_C@~@i{EE+-R85iNqR{scSq-WG{5ntgBn- zcViRKE?tkgiq~ZW*tf;bRE7!;fnVm#Pix_^UT8h3MTVY7%lNNDc*}@WDY*8L2N|nM zq3x1kNOjGX(a;>Wo;O_?Hc*$}L3olzUKEjCJ$&au;~cgXy~cxNxv#DI>O#i~%LCQk ze#~|DdmSknKS>VcJx;r(o~n2Ozq)c})J5iJld1zP)*$XIz)}LA7rl9qfId^f;wBhp z89S4WB;~93O$m22&35K{35T_!!`i&KVuUt(X4DVK%Cszn#k<*`IzsS{yca#tJIV60 zM;(3#GGj-n?#P>CgLeV(x}H8ZA42d&@JD@tz3L6Pm;JA)WU?g)MTg%Wb^2O7Jr(*| zC~Rk;U#X%r0Y{1P^94j3(oTGgjCqlg`sdTS8uui4+y(W>E!P3ZH~#Ht86=YBsoluQb==^| zoo~{#+@9Ac`hrpY#ai(NQVpR}A&F&y1G_p#OHHPc2ND=A?a>}ZRjOV_o2u^y3?G#1 z9k8k|QyXtc(W5zFqQ5aXDppMq6{~k(>&?>$1FRaW#;KQYjNWgnjY`?p=`4^=nm3NA zQ5%?&?3lg4!DChbCcz@z?BUd|agVr6!5sFA$ z092@#9__~3G}2(U=qU*EGu024nr|!}D9tpco+GU^mO@Zz$zx%PM(W3gseYaQb683n zXoaX!PqM5}(MQ7U&tAygVHhypwe;7gz^hHwSGW(YU)lfFl(WcBR-eXUjE%o8G4GUu zRIWO>d{*P!OrD~C)2)!MI`~Sc5Yn-)0vMCg6Lsm8jJjhepSuf?nu?K9toC|7A5_jh zY|v>xSyn-Xl6Y@EmZUo&x+VPj{)MnOdwQ$BVM_W9sI+c@NiHuR(T{`8LaWeK#L33S#FYk6CZD-%B#mnU2y2ge1AUD;2^ z<7>)fZt)!Ds<`G{lnZ)i(xyVY72}4?>ybiRgn-14IjUpAHlToPc790w5JhI%o}x~| zJg|ZDIG|uEzDt%T4-|31l8q+{Aj~S~?0;Z7@inb9%|*V*Jk31VJeg85p*S_abpDAQ zkA02((zSOc;|3*k#jBEChz=C)FtHKX4WY03iMdYQJ>6rPL*{PYOBi%dNJAxMl zZ=g@3PrgsWhsOK)%XjZ;pYkrnZq;tt&lI2L59xQpcZ2u(m%}^gJED_r_6*Aus}ze8 z4yoV>L>t5<+(n!!&I(Rj0Mokdvh@+`x>d`XLyS?#Z=e2vU@8QAoGyi|6h8h|mR5n4 zbh@H5S?<`Iki;p~E@^HS2|@F-PYtv0it6f)AOh?4<24UFUgxf_mEPRSuP8GDD)}BG z!T8mx2Gm25aV$8b|376d;)q>N!t??5a zc~^R(5YoCAcS&fDUG>&dc~vw`F=EEJ5yP%iBadLVYmULXAFvwAA+AU63lZm#hbqGb znune)7Eg^PkIxeEG&)BfRuI25;uf#CNz6OSpdyA8Ypf!I6tCix))3F^$yu1FEZoT! zE}=>kl^Zin!Io8(S8heBFFI!lHBpd$WS%DKeC+nZQJEuo%JVuH;q_PNggmTKDGs48>!PGTpM+(j!$3eI|HQ@WIX=h2(4vk-U;39L#U+ z_x{Q7Z6JGZ>&`GlUm>K6>NrYf&*MxE>c&B>@;PBF-XAIeP!e#w^=K(>zk? zls=wtIYOgNX0xyTTxlC?SEuhbqOd~oy6=mhDC(rOId5^K@_2gfnfH;GRZ)CY>Y0{R zX+P6^vW8&m9tpGS({Gc($$%FnQ9onsg4a334#?m7!UQF6ERmvY-f)~!KQ1ZX{hadL zf@8tJs+n?qzO;8)HOI10i5q00_I`lHsX3VZLp%JlQ-Kc%85yF0g znk6;WpS7Q5tJq}`Q@pHdthvJe;L$#M(a?UDeQxlY=H34>NZ2@h=IGUzbpz!d&_S|^ zqp|65=v_Sf+*j&$l7UscVCB4;iBvpy>;#obVzJzM{PsJN$7HgFaT)sru#&w$^>}#? zd=(}4!e>Oa;74OqZ`EK^!A+5cF7fVjX3S}^(lZ@(Nh9atDx zOdyb%9*pd7-y9>#|FxUHTrl~dzYy7f^)*1>Kk0w4l7Ak-zkPN{KtmcZsK2TJIT&^H zU!dS$O@IjK%m79RcJR+b2JDUk#RX0?fYE>n#{B1cM2ui6V6Xo*`M3O+^`F9>e^+ge z{SWY;%HTi`hCuwczUO}mctAj8|4Uy0{WBK$p~d|-UJWcds|yg-LuP}aXu5s3dU5#+xW5fqSfVVsqJQT`8UqlyI#=O69= lkU;*M_VP+;w6A=;7m5a2be!0icr}B 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 Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Strategy) */ /*: +🍪 Template +----------- + +The Template Pattern is used when two or more implementations of an +algorithm exist. The template is defined and then built upon with further +variations. Use this method when most (or all) subclasses need to implement +the same behavior. Traditionally, this would be accomplished with abstract +classes and protected methods (as in Java). However in Swift, because +abstract classes don't exist (yet - maybe someday), we need to accomplish +the behavior using interface delegation. + + +### Example +*/ + +protocol ICodeGenerator { + func crossCompile() +} + +protocol IGeneratorPhases { + func collectSource() + func crossCompile() +} + +class CodeGenerator : ICodeGenerator{ + var delegate: IGeneratorPhases + + init(delegate: IGeneratorPhases) { + self.delegate = delegate + } + + + //Template method + final func crossCompile() { + delegate.collectSource() + delegate.crossCompile() + } +} + +class HTMLGeneratorPhases : IGeneratorPhases { + func collectSource() { + print("HTMLGeneratorPhases collectSource() executed") + } + + func crossCompile() { + print("HTMLGeneratorPhases crossCompile() executed") + } +} + +class JSONGeneratorPhases : IGeneratorPhases { + func collectSource() { + print("JSONGeneratorPhases collectSource() executed") + } + + func crossCompile() { + print("JSONGeneratorPhases crossCompile() executed") + } +} + + + +/*: +### Usage +*/ + +let htmlGen : ICodeGenerator = CodeGenerator(delegate: HTMLGeneratorPhases()) +let jsonGen: ICodeGenerator = CodeGenerator(delegate: JSONGeneratorPhases()) + +htmlGen.crossCompile() +jsonGen.crossCompile() +/*: 🏃 Visitor ---------- diff --git a/Design-Patterns.playground/Pages/Structural.xcplaygroundpage/Contents.swift b/Design-Patterns.playground/Pages/Structural.xcplaygroundpage/Contents.swift index e7387ef..bc4f44b 100644 --- a/Design-Patterns.playground/Pages/Structural.xcplaygroundpage/Contents.swift +++ b/Design-Patterns.playground/Pages/Structural.xcplaygroundpage/Contents.swift @@ -126,9 +126,9 @@ Component protocol Shape { func draw(fillColor: String) } -/*: +/*: Leafs -*/ +*/ final class Square : Shape { func draw(fillColor: String) { print("Drawing a Square with color \(fillColor)") @@ -146,11 +146,11 @@ Composite */ final class Whiteboard : Shape { lazy var shapes = [Shape]() - + init(_ shapes:Shape...) { self.shapes = shapes } - + func draw(fillColor: String) { for shape in self.shapes { shape.draw(fillColor: fillColor) @@ -161,7 +161,7 @@ final class Whiteboard : Shape { ### Usage: */ var whiteboard = Whiteboard(Circle(), Square()) -whiteboard.draw("Red") +whiteboard.draw(fillColor: "Red") /*: 🍧 Decorator ------------ @@ -377,7 +377,7 @@ computer.open(doors: podBay) 🍬 Virtual Proxy ---------------- -The proxy pattern is used to provide a surrogate or placeholder object, which references an underlying object. +The proxy pattern is used to provide a surrogate or placeholder object, which references an underlying object. Virtual proxy is used for loading object on demand. ### Example @@ -388,7 +388,7 @@ protocol HEVSuitMedicalAid { class HEVSuit : HEVSuitMedicalAid { func administerMorphine() -> String { - return "Morphine aministered." + return "Morphine administered." } } diff --git a/README.md b/README.md index 864acc9..be2896e 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,14 @@ A short cheat-sheet with Xcode 8.2 Playground ([Design-Patterns.playground.zip]( * [Creational](#creational) * [Structural](#structural) + +```swift + + Behavioral | + [Creational](Creational) | + [Structural](Structural) +``` + Behavioral ========== @@ -126,6 +134,9 @@ atm.canWithdraw(amount: 30) // Can withdraw - 1x20, 2x10 >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Chain-Of-Responsibility) +```swift + +``` 👫 Command ---------- @@ -291,6 +302,10 @@ var result = expression.evaluate(context) >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Interpreter) +```swift + +``` + 🍫 Iterator ----------- @@ -403,6 +418,9 @@ spamMonster(message: "I'd Like to Add you to My Professional Network", worker: m >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Mediator) +```swift + +``` 💾 Memento ---------- @@ -557,6 +575,9 @@ testChambers.testChamberNumber += 1 >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Observer) +```swift + +``` 🐉 State --------- @@ -625,6 +646,9 @@ userContext.changeStateToUnauthorized() >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-State) +```swift + +``` 💡 Strategy ----------- @@ -678,6 +702,87 @@ upper.print("O tempora, o mores!") >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Strategy) +```swift + +``` + +🍪 Template +----------- + +The Template Pattern is used when two or more implementations of an +algorithm exist. The template is defined and then built upon with further +variations. Use this method when most (or all) subclasses need to implement +the same behavior. Traditionally, this would be accomplished with abstract +classes and protected methods (as in Java). However in Swift, because +abstract classes don't exist (yet - maybe someday), we need to accomplish +the behavior using interface delegation. + + +### Example + +```swift + + +protocol ICodeGenerator { + func crossCompile() +} + +protocol IGeneratorPhases { + func collectSource() + func crossCompile() +} + +class CodeGenerator : ICodeGenerator{ + var delegate: IGeneratorPhases + + init(delegate: IGeneratorPhases) { + self.delegate = delegate + } + + + //Template method + final func crossCompile() { + delegate.collectSource() + delegate.crossCompile() + } +} + +class HTMLGeneratorPhases : IGeneratorPhases { + func collectSource() { + print("HTMLGeneratorPhases collectSource() executed") + } + + func crossCompile() { + print("HTMLGeneratorPhases crossCompile() executed") + } +} + +class JSONGeneratorPhases : IGeneratorPhases { + func collectSource() { + print("JSONGeneratorPhases collectSource() executed") + } + + func crossCompile() { + print("JSONGeneratorPhases crossCompile() executed") + } +} + + + +``` + +### Usage + +```swift + + +let htmlGen : ICodeGenerator = CodeGenerator(delegate: HTMLGeneratorPhases()) +let jsonGen: ICodeGenerator = CodeGenerator(delegate: JSONGeneratorPhases()) + +htmlGen.crossCompile() +jsonGen.crossCompile() +``` + 🏃 Visitor ---------- @@ -771,6 +876,10 @@ The abstract factory pattern is used to provide a client with a set of related o The "family" of objects created by the factory are determined at run-time. ### Example + +```swift + +``` Protocols @@ -903,6 +1012,10 @@ let deathStar = DeathStar(builder:empire) >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Builder) +```swift + +``` + 🏭 Factory Method ----------------- @@ -1011,6 +1124,10 @@ Eduardo.name = "Eduardo" >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Prototype) +```swift + +``` + 💍 Singleton ------------ @@ -1118,6 +1235,10 @@ oldFormat.angleV >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Adapter) +```swift + +``` + 🌉 Bridge ---------- @@ -1191,11 +1312,11 @@ protocol Shape { func draw(fillColor: String) } ``` - + Leafs ```swift - + final class Square : Shape { func draw(fillColor: String) { print("Drawing a Square with color \(fillColor)") @@ -1216,11 +1337,11 @@ Composite final class Whiteboard : Shape { lazy var shapes = [Shape]() - + init(_ shapes:Shape...) { self.shapes = shapes } - + func draw(fillColor: String) { for shape in self.shapes { shape.draw(fillColor: fillColor) @@ -1234,7 +1355,7 @@ final class Whiteboard : Shape { ```swift var whiteboard = Whiteboard(Circle(), Square()) -whiteboard.draw("Red") +whiteboard.draw(fillColor: "Red") ``` 🍧 Decorator @@ -1475,7 +1596,7 @@ computer.open(doors: podBay) 🍬 Virtual Proxy ---------------- -The proxy pattern is used to provide a surrogate or placeholder object, which references an underlying object. +The proxy pattern is used to provide a surrogate or placeholder object, which references an underlying object. Virtual proxy is used for loading object on demand. ### Example @@ -1488,7 +1609,7 @@ protocol HEVSuitMedicalAid { class HEVSuit : HEVSuitMedicalAid { func administerMorphine() -> String { - return "Morphine aministered." + return "Morphine administered." } } @@ -1514,3 +1635,6 @@ Info ==== 📖 Descriptions from: [Gang of Four Design Patterns Reference Sheet](http://www.blackwasp.co.uk/GangOfFour.aspx) + + +```swift diff --git a/source/behavioral/template.swift b/source/behavioral/template.swift index 8a0188f..cf1f60c 100644 --- a/source/behavioral/template.swift +++ b/source/behavioral/template.swift @@ -6,8 +6,9 @@ The Template Pattern is used when two or more implementations of an algorithm exist. The template is defined and then built upon with further variations. Use this method when most (or all) subclasses need to implement the same behavior. Traditionally, this would be accomplished with abstract -classes (as in Java). However in Swift, because abstract classes don't yet -exist, we need to accomplish the behavior using interface delegation. +classes and protected methods (as in Java). However in Swift, because +abstract classes don't exist (yet - maybe someday), we need to accomplish +the behavior using interface delegation. ### Example From 204200dafdf34f9a43e36201c92b45cb8e71ba2e Mon Sep 17 00:00:00 2001 From: David Orriss Jr Date: Sat, 17 Jun 2017 10:28:22 -0700 Subject: [PATCH 10/66] adding a common implementation for completeness the whole idea of the Template Pattern is to show that you can have invocations that are common across the concrete implementations. so I added a sample --- Design-Patterns.playground.zip | Bin 151298 -> 151348 bytes .../Contents.swift | 6 ++++++ README.md | 6 ++++++ source/behavioral/template.swift | 6 ++++++ 4 files changed, 18 insertions(+) diff --git a/Design-Patterns.playground.zip b/Design-Patterns.playground.zip index 7510e583ebaf02988949596229e4133cdfcfa55c..081ca6eccf4bb7cf087103a765734b76cd66fb69 100644 GIT binary patch delta 6944 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 E0g{+36aWAK delta 6837 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 Date: Wed, 5 Jul 2017 13:08:07 +0300 Subject: [PATCH 11/66] Fix typo in virtual proxy pattern --- Design-Patterns.playground.zip | Bin 144523 -> 144522 bytes .../Contents.swift | 2 +- README.md | 49 +++++++++++++++++- source/structural/virtual_proxy.swift | 2 +- 4 files changed, 50 insertions(+), 3 deletions(-) diff --git a/Design-Patterns.playground.zip b/Design-Patterns.playground.zip index 619cdcdac5ea6cb27b6d1e0a08eab00cbf50eeda..042edd5efdf63c91ea3786932bce091243a41007 100644 GIT binary patch delta 671 zcmeBv$S3*Npda$v|E^5PN|YY;Vk z_+S7vf)8ZGiHR;^(%cLT(yG%LTNu@+*BUTsZQs++c$dp*(=opzneP{^7x-n+zP5kW z%iQfo?`G}ol)jmj-O;jQb?%fE|5k?nwZGD#_C6uw^HAPA?%@9_KHj_7mRigp4>#R1DFF0tX%jqzEMv~Cig-UF1&}H&x zf`kWH%UgXWUtW};nC@=C)Wvjt)^tN%CS|zG<)<4OGRZMcogQGwRKvtHXL_I^Q{eQ1 zIgE1CZH<_;n2gtfMC_;cuVWOQzSoFJgJ~f`M0mQudWb@v>B+`Sa!gAOfK^XB$S4j{ e%r*TnNL1t?#EgQ2jKr>3Z5s++d3lMs3f} zWvpfb+dchVKBG00m&0@(14iBH3B8PL)A^ejWu`auGIFs5IL`Lm-ci6PAdISFpDq)! zito*g+}v;#0<#&Fz}oph+V56A@0Q_aV31Os&e+1JKE1|(No)I_e#X08&PK;h_i|jm zXB)5hIgu||KJ@VIyx2Rs)xu_*u3i)13=F@m;r};y^^f`$yuSAiUU>F8IOVF@tAZO5 z1)0Kp-oNBQp)>uRE|b*scTJ3nAcJM5uh(Z1o^IF77`1)=Y{v7}5FZv@XLJR#w(q{q z_{4vDxdxNK^!4gY0W6?U+s>@Pl)(gMPS4k3%7n1)XfZWIbSG;wd4v2`sR1&~>M(tV3+w4Zg}2x1GWj#X#oy>N`SPNK!gMzSrY^=C(=Qq@)iO<+J$<1BlPoB* zm8O4~%_uT`j}a5s^tFaea!kx~Q00WC=g(o3n{H#oq{U>i4oR+W9iu2np9a$+G+|-5 f7M|%z#!PaIOQ$y)Gt~o?Gnz0pvn5|=1SS^%NOaGJ diff --git a/Design-Patterns.playground/Pages/Structural.xcplaygroundpage/Contents.swift b/Design-Patterns.playground/Pages/Structural.xcplaygroundpage/Contents.swift index e7387ef..1cecf7d 100644 --- a/Design-Patterns.playground/Pages/Structural.xcplaygroundpage/Contents.swift +++ b/Design-Patterns.playground/Pages/Structural.xcplaygroundpage/Contents.swift @@ -388,7 +388,7 @@ protocol HEVSuitMedicalAid { class HEVSuit : HEVSuitMedicalAid { func administerMorphine() -> String { - return "Morphine aministered." + return "Morphine administered." } } diff --git a/README.md b/README.md index 864acc9..d108aff 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,14 @@ A short cheat-sheet with Xcode 8.2 Playground ([Design-Patterns.playground.zip]( * [Creational](#creational) * [Structural](#structural) + +```swift + + Behavioral | + [Creational](Creational) | + [Structural](Structural) +``` + Behavioral ========== @@ -126,6 +134,9 @@ atm.canWithdraw(amount: 30) // Can withdraw - 1x20, 2x10 >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Chain-Of-Responsibility) +```swift + +``` 👫 Command ---------- @@ -291,6 +302,10 @@ var result = expression.evaluate(context) >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Interpreter) +```swift + +``` + 🍫 Iterator ----------- @@ -403,6 +418,9 @@ spamMonster(message: "I'd Like to Add you to My Professional Network", worker: m >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Mediator) +```swift + +``` 💾 Memento ---------- @@ -557,6 +575,9 @@ testChambers.testChamberNumber += 1 >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Observer) +```swift + +``` 🐉 State --------- @@ -625,6 +646,9 @@ userContext.changeStateToUnauthorized() >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-State) +```swift + +``` 💡 Strategy ----------- @@ -678,6 +702,10 @@ upper.print("O tempora, o mores!") >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Strategy) +```swift + +``` + 🏃 Visitor ---------- @@ -771,6 +799,10 @@ The abstract factory pattern is used to provide a client with a set of related o The "family" of objects created by the factory are determined at run-time. ### Example + +```swift + +``` Protocols @@ -903,6 +935,10 @@ let deathStar = DeathStar(builder:empire) >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Builder) +```swift + +``` + 🏭 Factory Method ----------------- @@ -1011,6 +1047,10 @@ Eduardo.name = "Eduardo" >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Prototype) +```swift + +``` + 💍 Singleton ------------ @@ -1118,6 +1158,10 @@ oldFormat.angleV >**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Adapter) +```swift + +``` + 🌉 Bridge ---------- @@ -1488,7 +1532,7 @@ protocol HEVSuitMedicalAid { class HEVSuit : HEVSuitMedicalAid { func administerMorphine() -> String { - return "Morphine aministered." + return "Morphine administered." } } @@ -1514,3 +1558,6 @@ Info ==== 📖 Descriptions from: [Gang of Four Design Patterns Reference Sheet](http://www.blackwasp.co.uk/GangOfFour.aspx) + + +```swift diff --git a/source/structural/virtual_proxy.swift b/source/structural/virtual_proxy.swift index ca11ef8..af5d7c6 100644 --- a/source/structural/virtual_proxy.swift +++ b/source/structural/virtual_proxy.swift @@ -13,7 +13,7 @@ protocol HEVSuitMedicalAid { class HEVSuit : HEVSuitMedicalAid { func administerMorphine() -> String { - return "Morphine aministered." + return "Morphine administered." } } From 5527eadcb6efecd8a8f729d7bca7149a109bad3c Mon Sep 17 00:00:00 2001 From: Ennio Masi Date: Thu, 20 Apr 2017 17:01:04 +0100 Subject: [PATCH 12/66] Tried to make the Mediator pattern more generic --- Design-Patterns.playground.zip | Bin 144522 -> 150075 bytes .../Contents.swift | 35 +++++++++++------- README.md | 35 +++++++++++------- source/behavioral/mediator.swift | 35 +++++++++++------- 4 files changed, 66 insertions(+), 39 deletions(-) diff --git a/Design-Patterns.playground.zip b/Design-Patterns.playground.zip index 042edd5efdf63c91ea3786932bce091243a41007..24da3bbdceff0266419291ed7a6d502134311abc 100644 GIT binary patch delta 10826 zcmZXa1ymf(wziqU-QC^Y-GT%UL4pQ%cMFZX+aQ4u+}(o)cMpTRJA^<2AwT)fz2}~L z|L)bc_kOFYYpq^W^Q<@K80kwIGP;H`EF22V-_0i?Eg4+^_T>^R-z*O*=fGYLPgD9Q z^HocHb#ep+fd6&|Id=w$!MR4JDM4PUSRp3yAOr|zD2NOa6c0kd@O(+UDM{?2 z#esp@mVto6K#c#&)+B;30Z~{LeqWE&upon!ATtlKQgiIrAb5A!DryL%MuG`u_1^>9Ww@ z#f8gydN6xaQTzJiZ&wc(Sjs7uKGJffy!Wadhvm85HWdPnD=4L34uRvNt=WJDY*O+s z(>CAFEJy8{9h`jWGnsT7@Cs7)?S=@*?^PDuv>VW!N#3OM%R-;uH6Ea+W-*bruQh1l zhqD~38;qsFotqFAwBr|8*j@W43rN*Y5ZR=TJHyXlH@oB``*&MrfrF*S^qf;hdEoho z^bU3k4Mz+G42Ue4Yk>;(ow61XnOZMbs~jPS&P!((=6?eZ5`wB_z^mFt>%vG zsvIj`Ng*st92K&y*3hY>O(N-%LIp%xJqNADx>$pDhcn3g%9e>JdiK6QPs8_rrl!7; z(FHVG^x)pfr#EB!fA=}G=Iby-&A`di5BVG*W{-xT)Y3fit`LBhXqK1Rd-bz2&olrw za_bAc3_cz5IIZ@`nDColm3n1vI!#*}^cn{eT;bS2Zzh;WdM8Q=e)3QUcvbBqm$C_GHYZXCS;D~lNQUX2zhPhH zfmdhk0gqea_vBuIGrmwCmz-Vm{xB?GTN$XRGz}^UJYryPRt{w6(4x*87yGn!gCu_N zfdwSmX#qEaA(mcxMl9-)zZov$lZ}{hl;0~Yb=fAQe*=`)60v?6Cz&1{APqK{5G=yD0{+!s<~tUzh0) zkcKq584x^2rNwr&xK5ob=f~aqo!*X;ZXoG*@WZ7kS>#P)N@ZXLwLHR5{m77np;iL? zxZVqPo&cBP(*p9sJh|A=O`)dx$e4+M)gS3sjEFbWGU}+sm}HBD$OKD-Q>wW3nMFO@ zX$NTTzdj2hBcBsxZL%s#We>gL=h}FPgW#oM+fQ}pVPRT7e0UZh7ft+H6}-SO71Nk>_ObzCU?8fI?*CXrTh_8l}FG zwH0Z3BF1m2->8x*5F90JnPw|86G`N{PY=*ub@SCbVk*h?P!%%%z}6@1ZCD%y31l-- z^3U*}T6v~jLK$ddj#WVeTlR+w2c}lPGoL3u9-j2@o|hL9%|vk=Llh$4M#K({Yw{=6 zyah1y@94} z%A*6m)UU&U7K@1myXH4;QtU^9vBvkU`0e@SqIN6`#zz&mj=G?e8094gemqCk{ACUt zrU#4~Q)}%VgFq>&#PS=zC##=ARh?yi^ZUT^`Ygg7{842npE5a)R09| zEY9SL2d23e5K046-8)CPw(t-K>RxroRZ_o3I9S0>xQu`_UB>oWrhKf-c?VmLQx*u= z31^+q7E$h6j+)zxBT?k&tBdIWGmU@erFOJx`WISLN%3oCOZd#maB25=R zTqPXBA9B_n+7exEqe!eu&8@5|o}%r}7{a4qA5kGUE|9xdh_hA6f4l`uK{PB#hF5=> zzB!LMNsxT!S}-SnBg=wI|2;>6E3@q+8_!i4E!LcRqV=@Ei%TEokGB4Skn6hJjdfpk# zY5K+IwqzEGUG(93GDZ#)!#*=0^S!U7dCh|7m#nlTT(J*TNTMf>biYAwY61nyWTgcZ z^KiNO2K-VZgQ4Hj}KJO>$egazu0korqCvG7(ZhIccK1xjn;Det~nYz2jm5yac8K$rgE{% z$IJDXaaRx21TcLV6Ey9v11Xfa!XCECujic+X#MNXR-V;TqwtQ6nGs~?H`-^l270;Fs+qnf)xZh6iNuJSaLOWC;IjoQ6D(r=LAS!X|j4V<2ke;I&E(y{P zbJlwhIu@UDJ$-fVOiVUBT}|2i?yVoMJ+2n@b0^Ge-qSgkayXbfvd zxNtHEmmpjqOe6wuqLw{jL$%-huLUq_Qagv;AyAcTiW!Y( zpCb^+r*;8h);(?1Y0=xl_n&8;$gfd@-yAv>`OoWceEjsqdHp(E4Wm44C*NVFIv|V{ z8p7%_{OpRDZPyBAkdY?S*Y0Gh3pm!Z#zG?Zt$n}hs>$c@O=cNEhkTAZ;SWD|wm#Yo z5E}k`DI@0+T77sPkr}BhtA`YfsB<1CJ^84uZj%RC;v!1ks|cbO#L{P8O(H;g;|J7> zzgm*4fXu^agWnYFavdE`yyD@iZHDHD!j7Yx z^W`>h9FK>&OrNGxyhopZXZhMsSrumu9nG%$&4L%!SKc2=#;9=}8tDzycGuSdu_+v$ z?TE%dNx)oC=QX|d=^wZ0LF9(p6Zl z?@o@=4BnJ7a@@c>IYfx-5rcHL*qPDv_)wP<>@Q|aT$QA-Msa2u{`N5A%9jl(TOJAj z!Z$o(R>kY>@tY|g`@6*);x+88bFU@mjM=SFPCgHxP!GO=Btw3mWySQLr8+9`J(MT| zAb&s5hCP~nIBv)xXJ$3bJz>x%xL`hrbyw6?>rz4LC%x0_ihdFC#c)nG^NtGfxcKd` zSopk})$gs?*8VFB*xy6Z2^uRG30cGsL0&C9hSD68^=|i5m|`^V^^(CP`VyZ8^4vuX zi2YZ#7|&z9zwwSbCf@1777na8zvlu>fbI?Vai1YE?SqU}Z4Hr6uK6H-5l6~5E%2fS zvEP4Hr(A@MwSAltpCMA~o(0h!JoAS5bQQvUW+klOn^7{?e#Qv7LA~X#uP)o{&m^8z zi83`~@f!afH$MbybZhpbjnxZYp?Q$uy4H19-6e^ zr}617+~c-W4)36$XW%JkH+YAHKw%2cjg%y3A)8IyA*b&)jF;Z@P`L%@R*>XkN&4E$ z%KUuZzcH{O^)6>$Q>M_fgzGi{h;xUVU%Zo9-^e+KjC|`n(rFVrz$X4>V!~0oS1RMz z_KQOTPe6B8-X?aksQ>8KY|k^PeR#w)#{oY%{bw7IWH^Oro$Q=o+TC@=* z+BS9KMs=Z}7I;}O@zm>0X}TfOZD7P7uv|Gw`v9R$Il{8OpZ_m8rU?Noz`aEWUqFyN z!uy8{>+MqF&!TLtRWWn(bQbOD^7(KJ09_Y5;ZL4{*5 zOpRx?GhZCSZMPDmDgEb7IQKB)*6%$R2ScIJt`JECcaMqbuY?M-I)qp@eRP+12Gyn| zjhcCMqSYk$999;?g-f?d!0H&<0CY59DdcQR+>nwe`i8=zBF`K>;GFTQe#6rYGl~by zjzh5)KE$!TphLg1T5m{XBw(>auu5ON!M?hAXXbi)Hr{ziUI?T6xBh zZ`5aVa68fCS))-RsaEgLpk?85ctr*KE~(Gj0Qn?T{8QFfqfA$uwveJ)8h- zG3xh25{ryEZrL>(>>#9oxYBu?=>P?sQX~K@CE_D7)zk8T+{`X$9m{2_!9(eBnMAQN zc}XhpPi>rAe;EYMLzHL|W?>l=^>a|k;I3mRd#6Wqcs9+DPhls6%`&w^RJv$BjjH`> zGQ!+Hdo>{F+;S1fNUU!rD?tEmy)Hw=j=EIVlVDHre%0);e=o&Pi^@_fp69R|`?a7t z^(cwd>vf&_rKQ;6uwQ*`kyAi?-o=^PRV=|LYq{E^;Zp;`#_QYQ?mRlwWCF-oD&1aK z&TU`l$`PPjUm$O$Kv>N|WZe9)*iUKu zqr2Yeq69N8QeW2K{@+DJs)5P@jyAJ{b)2&!@y z5$k{X87T_vblZKXiE=)9zUaJ?blo>`XeK9kZqACPAU^rT?ebgVZL#(+1ja-e4`&mI zAWN#18n!Z$qN>$04ZN2h{&10Ne`_H86u+gvICFF!e`s8e=}^5FcwT%8FBUHap!wZj zgh16%Uqzp^N?SVKeTqDjzu#)v4X02Ro`vJ{bD;sGSN$VlLSY43HHOs=d_a#*u-Z$+ zwS#gWZ@SosXXA%b3EGQ#>2uE7ZhVWKfGRR?LRtle58MTV6w-6#a6dz=?}PJGk3C*( zMOU|f#v1sPvqQ>O)w>(>X&GWXg7Kyy)KjVfuKUy3Au8%nW5>u91Tej{WbY@nBPVqF z?!yMKEr0>J;9w8|EatUyUAp=mGs=V}?vC-z$dR_8w}FZ@xF5FW%d;c@Gc+k1|JGiw z4r?I{-lW9`DYW-hh{@J!M)l_}P(mR$Q+2iCtrK|$W{aOxp88ugC$u+yVJ6&B}U}iWs{;P3DYcdJj;wxe*(dAjD77MT!!Tt+BsUZLB3n_p2EY*@f=j}IAsj>%RjtWWKpUxQBm>a}1w z<@g&P32UiY(92cs$blhWLBxTT_g;l-m8PPDX3&{~LXV2)STj9RDqY|3?PF<^i(;XZpTAZ?#u|Y1?lN@QT^{I!sMz)wZd8 zj+z=rFw`&&68CO(Q#0BRc|7O;l7U7pOc1yF$M{BqX4sB#4~E zi4+F*3+)J;2u-xNtFGiT-DXO5OWNcyw%_O7cRu=0`2wx+)e_E34)vWVa7=W;XnXlU zzQJ+JPvY@#lM&LZ>1iZBW9GL0&+xlA7<1M9y{wFZ9=^!>hK^&v~>d->1ggRa*5+K2oZ#<@4=ir@)b zt#5N1_W>~grF5J30i`<}=<~jE7Lr|{%R-|SNs;*;MqBurgjjYc6`3yfT~xZz2p&(o z3L_+?-9kd|l@Co4eNi-Dstyjrxdr|)jr|CNoA|OyOA_gbqXl7m?iqu)1*fnga6xmQ zqA-emL*yIt6rq(|I_kdXy(f1=;v4#u)v2(-2+)>}5bi18;QwUQe#5U?5_)7J5{6N% zUr{J;S76H*s#dVPpjJ9#rZ1yx3!kgXYD=E0u)ZJ*-w`G-Yekap=pk$*2S^Lfvwx3R zK?8E8y~!4m&_YeP&_c0qSt=WWobUt<@yByiBcq7b;YgV-F1QGq!6M_CUYE4(E*mdf z9yj;up8}QDy@pzQOaiOqXO&P*9WxGg7LL08^bC3eau`aJolj#XeMyDE=eeapULpcUg1}86C<8S&L$z4XClat1i1}?+LKqpEBb?cgANu=(rib0;i?akYirb_i{7cEY z`a3S!(Z@10b;7a;Dn8Ik7K5DKjns(oOf7mv?32r40(g%2S?B_iGI~BSFfwBws87DRI7D znRjrpeek+4nDHZ~EXHAlE_@~1L}anYnXXu3RJ}MEM~%=!B^v}vi!GrEx!~eQu^-5$ zM78Ei0uU>o@)_v21v)syqfa=uTW3KEF50}!;sG;nFJq4k0bIN=xeo+NT2*4FMf>_4 zwNCa9rnskwS5a40F?xj9EI+;INSW|6t{l6sf=X>aBv!oY{>)Vw(k^4KfmDwwF#*R7 zv3mtyuoBx?u%VA!N!5rblKjDQ+h=sFBReyA-}Ey*9sLiIql@s$ZIX{c%Qo>mZ3F_n zQO55OPhDx$PJr-u7jm^BHa<=>2ZW5Gi1k=9>s!@8=e9{&wkThYE|-2dtUpCD%P6Y^ zIyw-)^@5v#r1TLT7y143pq$;kb#SX0hW^05>$?Hb-vT9sEn6@xt^F5+>5Gl4U&Si- z6wl91r{CSZ?(eFL6c&=7;S9taV0J+~BNT7JJQsI?xdmP&#-~mkDbKryQ;%&q39<1A zh5ZzF!4#R%;mx@plBWz(Fd3lm!J-I>oQ;MTvcwb{)4b*WIF>TYz9P)6MmFA7r!hJ9 zbrY{Wj+vsI-bk!^%RDx2OZf3;u}r=k5~664lq7SFNzYKMtBqE9>9()y`~$lf?DW?^ zy??&CUx@;paHZQGYy&iGLn*(nz)uv$VG!sczEDE(y9oFCgby`R6ppCYK3U2?x!%vu zvhaPk>@H(BaEPU`#-BaBem2WuVrO@FrP4n(;$$A@WFyHnBsV;^lJz)9a;n}NarEwd z4MqMKqsij7x>|yI6?ZD({p$kx9(2mys1H{dou~j1BH8bMB{9{j?8=a_Ybj(;`2_!r zLits}Vg0vcRj<;=P;H0FF0x5frFZz#NDpGvvm&hqNa5hV1ezX6Dq?}@Q)Es{S#4=& z)bZLfGyV;N;A%hiYKKBe`!eT8X1y^)UxJ=3!;MWkw(R3OBsq!qzDx@Y5q@iWsRexr zpYBkA#xwT^aJOME2Ki@~q+;|bFLYhW#jKA*&ug}jC`nsf8gJM?BD;BT#OqMCmRsSQ zFGFhaq$u^&27d}`s&38pT`Y?C5BBLJvcxy@(ybcz7$R~e?Ix{B14Gc7h1ucba`>f7 zR-k=}%XZ!jBkmc7tn*XJR8Bgja!t)t+-Em{<5cGWJk6$QW9(rYoaO88`2&mKI{K(w z+Rc>SB6p!1y?2gNaF)^Yw%&AV?cf|qB3sZL9F+&7UoPp_s5p|QnhN-0kMU#?u?(E6g&2%;&8dmfKGo{?mz3L}WaPSQQ z|2!kK2wLgbAbw84IV8rh6)}Hl8VJbV*jU<$CN$@A#FJshFp?fj_EhARTp2wV3N0T$ zA=+Yejj*(HgDea`;dWb9Yg8qcCy-tLs2kpV<$`c5(KSPQ97ol41kLT2?U(4N|2%K& z8igWUZG;N-r1;|H)g>Q90;ZM=lL0yY9n%Tcm|GwmU_6>^$d{~Qrpj}=H?0I0fe5q!>yyK)(86p#949mYwVr-6F&CDgH>9gn(Eux4VXen_>pw1ds z*ECj9LGf*hbE~gW>{u)Hr2L}ahM^2NsMKw`r$mgcE12Zh1?wh1Cl5d@n zIYgzcQrsA}cz9y9xTxtZFv@8lscAnapWnCU$K4Gm`B}#EY>^FJyy*IbO zTT)H@0n&4Gt7&THGf{Y0l_edx*U6S1iGqeo=)eA0zQ4ooYbuI?`si7&`uVOLYhwg5GB3`Q}YvBDs>Hg zy=xCkI8JwWg(&~^1uZ599MP!ko@pn-mszq~OTXxJ#&+9~ z9aH2OU&X4WEM5C`e%>q)99?xi>5|vn;(8;O`)55 zGX+S#9O)S)?gWUP`wXrjZMe>>3dqHL$U|?0N6#TBS=S9>M>+9&S@XUDW zGIpp7IxJeELR!M74!&8lkjqE*M^RMtt@SArT3AVbJAK=|`2u9cK43{_L2Ah{s3GwKHldt=68!j_?8a`r;rT?WYf_?44b*ujIK-f=jq z*YISHEO0n9S!pG6c}z&+|H!wsj+CoTSihghk$=||%rWqI6&L_Rxu#6`mar>?9l+e~ ze~4;&A}-pClJu&Rl~r8Z_~leA7_(ysz3;YyL8HjVMpD{aF)NXFx9=UF@<(Wh3w)mROOM1$<96EY<>^`Y>?J1|x%tPxtQ}L};^86EbQcLmT=@t~Ozy*;6WePB2(zW#GSxEHGS{*Tu&k&T!S+@_THtjC{dk6+g+P{31}AIA;@Db) zW5b7rB@4>2=zu0MRi_NXapis9J>GrDDC=JO4a-kM-}p|o4L0Xw#J%x7YTulI@J`tc z=F61YjN0VOB+3lRWJy-Q;5j*j1udpLMoBKztbPY2+<=-X8!tD;X%J!1Ge$KAn2gDd zp%|nXB##M=`GOybf6tP@Y^>8+?(^PN={kNV&aKX^&8P+u-yFUjg{1n``9^*`V&)lOE98+Pz z60TI-P|2c2p&eVHjjt81ZLejZ1sG_rY7164>8w|*l&=(v6m=+gemVgy%2p_7z3keF zm3eP-H9k~iR1TMwR$7;Lo$R03FW4`hE|4xPl?#>&R(e->mwQ+GFZwS&E+8%-E@D=^ z*8)C@iTQfm6pw0;-i@L*n>VL6Lu{0r8=F1#AuW2VCF^Bfs{XA%kk4~~6-m3z+2_}f zc|TxtjUgqZrKGhvWjR&uCrTds9eN$h9l{-c>oU3dr{5fB$Y;ch{9k#$^47W!xd^)u zUuW#7_1rw^p3i-)m)js=sXLaJM$4>T{834`xkk+^+Rap zCEUX{yesiPhmPfIXPrBjq2>YK9y+g^u6c1YqoT7dO12qNnHTwhu{0|Z`)miE95)r6 zw>8Yue3M$%JF1fhyIsRRN5a3}|>X^xLrq38SR)+}w@1B97*l zB&$OteL-N|-*jZK1e-|cyB>^Uaf zQd8a{f4UY1N*@v~e+JJ#jZA;s7JOcyVPE87*Dcp!rqi}-JXy>ax6{%m=06P*Su6}h zKWdt?(IE7E-A|&e=Bs+t+z=o?JvSFhVPz={s}@>P3dOSQ(e^2_tU_bC5>2|Y|d zXyKIbWyo;AqW6dC-R?_d$tzm*U&Zg~Wk(e?RW9h%sZt3?b9!<((tjN$3;#*({QY9w z1A!@E|83oaxGsU@|N7}#JC;EE>aZ`iJ4gW|*ytbE9heF1`A?*t6-?Ti&IJAj`X}zh z0=E0-W|ajT_Kz9Qj1{Z``(nm}yj0r!U-KO!8#o$_5DNKB1SbEtPmdGxKS%P{T zkSz?1@?Y`G_Ah<(f7bu6uIRuRIsa~pA410sW&uz9SLDSNNdvjc0pUS9dB7-;YHlzE zSoq_=s{cEO19AQcqJW6;yy)y|{v(%A1H%8SV**3}PZ;;#5;TYz@5@ZALV|h007w}E z;sbj^BwqTW`v17^zuxBMj0JNpowf8o9sL*3t>ys}|D*a}*!SP6zmtdn{r^-i7?>Ro U9^r4<_m`c;7zXC?^zW4YKQ|Q~NB{r; delta 5483 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 PzUzc00D$@QeG&f$se>z; diff --git a/Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift b/Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift index 89a584c..a3a740b 100644 --- a/Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift +++ b/Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift @@ -311,41 +311,50 @@ The mediator pattern is used to reduce coupling between classes that communicate ### Example */ -struct Programmer { +protocol Receiver { + associatedtype MessageType + func receive(message: MessageType) +} - let name: String +protocol Sender { + associatedtype MessageType + associatedtype ReceiverType: Receiver + + var recipients: [ReceiverType] { get } + + func send(message: MessageType) +} +struct Programmer: Receiver { + let name: String + init(name: String) { self.name = name } - + func receive(message: String) { print("\(name) received: \(message)") } } -protocol MessageSending { - func send(message: String) -} - -final class MessageMediator: MessageSending { - - private var recipients: [Programmer] = [] - +final class MessageMediator: Sender { + internal var recipients: [Programmer] = [] + func add(recipient: Programmer) { recipients.append(recipient) } - + func send(message: String) { for recipient in recipients { recipient.receive(message: message) } } } + /*: ### Usage */ -func spamMonster(message: String, worker: MessageSending) { +func spamMonster(message: String, worker: MessageMediator) { worker.send(message: message) } diff --git a/README.md b/README.md index d108aff..07a39a0 100644 --- a/README.md +++ b/README.md @@ -365,44 +365,53 @@ The mediator pattern is used to reduce coupling between classes that communicate ```swift -struct Programmer { +protocol Receiver { + associatedtype MessageType + func receive(message: MessageType) +} - let name: String +protocol Sender { + associatedtype MessageType + associatedtype ReceiverType: Receiver + + var recipients: [ReceiverType] { get } + + func send(message: MessageType) +} +struct Programmer: Receiver { + let name: String + init(name: String) { self.name = name } - + func receive(message: String) { print("\(name) received: \(message)") } } -protocol MessageSending { - func send(message: String) -} - -final class MessageMediator: MessageSending { - - private var recipients: [Programmer] = [] - +final class MessageMediator: Sender { + internal var recipients: [Programmer] = [] + func add(recipient: Programmer) { recipients.append(recipient) } - + func send(message: String) { for recipient in recipients { recipient.receive(message: message) } } } + ``` ### Usage ```swift -func spamMonster(message: String, worker: MessageSending) { +func spamMonster(message: String, worker: MessageMediator) { worker.send(message: message) } diff --git a/source/behavioral/mediator.swift b/source/behavioral/mediator.swift index a97b7a3..8dfc525 100644 --- a/source/behavioral/mediator.swift +++ b/source/behavioral/mediator.swift @@ -6,41 +6,50 @@ The mediator pattern is used to reduce coupling between classes that communicate ### Example */ -struct Programmer { +protocol Receiver { + associatedtype MessageType + func receive(message: MessageType) +} - let name: String +protocol Sender { + associatedtype MessageType + associatedtype ReceiverType: Receiver + + var recipients: [ReceiverType] { get } + + func send(message: MessageType) +} +struct Programmer: Receiver { + let name: String + init(name: String) { self.name = name } - + func receive(message: String) { print("\(name) received: \(message)") } } -protocol MessageSending { - func send(message: String) -} - -final class MessageMediator: MessageSending { - - private var recipients: [Programmer] = [] - +final class MessageMediator: Sender { + internal var recipients: [Programmer] = [] + func add(recipient: Programmer) { recipients.append(recipient) } - + func send(message: String) { for recipient in recipients { recipient.receive(message: message) } } } + /*: ### Usage */ -func spamMonster(message: String, worker: MessageSending) { +func spamMonster(message: String, worker: MessageMediator) { worker.send(message: message) } From e1f63cb3129fac45d5542e92115e19376052ec96 Mon Sep 17 00:00:00 2001 From: Ennio Masi Date: Wed, 5 Jul 2017 12:39:26 +0100 Subject: [PATCH 13/66] Update Design-Patterns playground --- Design-Patterns.playground.zip | Bin 150075 -> 150074 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Design-Patterns.playground.zip b/Design-Patterns.playground.zip index 24da3bbdceff0266419291ed7a6d502134311abc..adfa80d6a91403853dda93e4141a07754dfca17e 100644 GIT binary patch delta 625 zcmdlzg>%;wPTl}-W)?065U5IiI+53m8Avs{ZFOT@sV4|zdV!^&gwb@x8;qvXAT1(5 zAr6ohFRvNz<&uHCb|CfwE13SqhDl=kTz$quTaanf1#=mrK#c8qxr{YTV4=79j5f>@ zQ=U%0*vx1&J+6RJjrmN<)9vjAjPAl<1wio#u#ip*BM&!1X`d^T%yjt{MlN2Udan}` zUBslh85pFuFX(5~=eFB)%juVA7givW`&%7)T%>!0^^FbDBF-E#q|{ z84QvC?G7~K)&Yn%14Bm6>GlU1`KH^rF>y_=_5jLx9Ym5_e~?jY`g?aKp6QaFK)D&$ gA#xR-K)YFQz&S$GcOPVwo384`B*6CTH6ze&0E}?mFaQ7m delta 657 zcmdlrg>&~5PTl}-W)?065U6OIGLhGe8Avs{ZFOT@sW+X=fKh391Q1Mr+9hIcrTX>+gNdAMOhM$>cq8P#}! zO1A9#2Cx26zk=8I-oXpcUI(XKHG5TXBcdQvn9uu{{Pg)fjP}!eU77T!-|J(H+J1F5 zqhSEpshn>Z-9U`(L2nqJ`ZM1IddSL#DHiOZSvE|WOkl^c*)wH<8O8QYEnt1W?3sL+ z3frd(+A_&ZPjO)K1$k%s76+y;jOV8d*fPmZKjsJ#+%D$C6u<-%ZE<1pMfKtIdoD~} zOnkGae{^B8pZ?m3Nq+hXS0*{8Gqa~})CQUZj2NZq>TXOnOqO#{MTDlm^I+1N{=f~W zI%^$V&UAX72NTcqICr4%4TNy;^aXZIY}3EEGpR7$J^)v(G~K|Ek#oA;K}Npm1s+Tq zOx_34<<=c!)PiUh@&sz0c^yeX!VN|th<#H%f%dW8K$SC?uHwZc!1nt!BQOmC0Q{}x At^fc4 From 513ea1d8083d6b6b0493c431db2613867c982c23 Mon Sep 17 00:00:00 2001 From: David Orriss Jr Date: Sat, 17 Jun 2017 00:54:06 -0700 Subject: [PATCH 14/66] Fixed compile error and spelling mistake --- source/structural/composite.swift | 10 +++++----- source/structural/virtual_proxy.swift | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/source/structural/composite.swift b/source/structural/composite.swift index 4c5662d..fea9bd5 100644 --- a/source/structural/composite.swift +++ b/source/structural/composite.swift @@ -12,9 +12,9 @@ Component protocol Shape { func draw(fillColor: String) } -/*: +/*: Leafs -*/ +*/ final class Square : Shape { func draw(fillColor: String) { print("Drawing a Square with color \(fillColor)") @@ -32,11 +32,11 @@ Composite */ final class Whiteboard : Shape { lazy var shapes = [Shape]() - + init(_ shapes:Shape...) { self.shapes = shapes } - + func draw(fillColor: String) { for shape in self.shapes { shape.draw(fillColor: fillColor) @@ -47,4 +47,4 @@ final class Whiteboard : Shape { ### Usage: */ var whiteboard = Whiteboard(Circle(), Square()) -whiteboard.draw("Red") +whiteboard.draw(fillColor: "Red") diff --git a/source/structural/virtual_proxy.swift b/source/structural/virtual_proxy.swift index af5d7c6..9d59035 100644 --- a/source/structural/virtual_proxy.swift +++ b/source/structural/virtual_proxy.swift @@ -2,7 +2,7 @@ 🍬 Virtual Proxy ---------------- -The proxy pattern is used to provide a surrogate or placeholder object, which references an underlying object. +The proxy pattern is used to provide a surrogate or placeholder object, which references an underlying object. Virtual proxy is used for loading object on demand. ### Example From 6ac2afe9b544550102de8b59703e61585ca5f6b3 Mon Sep 17 00:00:00 2001 From: David Orriss Jr Date: Sat, 17 Jun 2017 09:39:53 -0700 Subject: [PATCH 15/66] new example for the Template Pattern --- source/behavioral/template.swift | 70 ++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 source/behavioral/template.swift diff --git a/source/behavioral/template.swift b/source/behavioral/template.swift new file mode 100644 index 0000000..8a0188f --- /dev/null +++ b/source/behavioral/template.swift @@ -0,0 +1,70 @@ +/*: +🍪 Template +----------- + +The Template Pattern is used when two or more implementations of an +algorithm exist. The template is defined and then built upon with further +variations. Use this method when most (or all) subclasses need to implement +the same behavior. Traditionally, this would be accomplished with abstract +classes (as in Java). However in Swift, because abstract classes don't yet +exist, we need to accomplish the behavior using interface delegation. + + +### Example +*/ + +protocol ICodeGenerator { + func crossCompile() +} + +protocol IGeneratorPhases { + func collectSource() + func crossCompile() +} + +class CodeGenerator : ICodeGenerator{ + var delegate: IGeneratorPhases + + init(delegate: IGeneratorPhases) { + self.delegate = delegate + } + + + //Template method + final func crossCompile() { + delegate.collectSource() + delegate.crossCompile() + } +} + +class HTMLGeneratorPhases : IGeneratorPhases { + func collectSource() { + print("HTMLGeneratorPhases collectSource() executed") + } + + func crossCompile() { + print("HTMLGeneratorPhases crossCompile() executed") + } +} + +class JSONGeneratorPhases : IGeneratorPhases { + func collectSource() { + print("JSONGeneratorPhases collectSource() executed") + } + + func crossCompile() { + print("JSONGeneratorPhases crossCompile() executed") + } +} + + + +/*: +### Usage +*/ + +let htmlGen : ICodeGenerator = CodeGenerator(delegate: HTMLGeneratorPhases()) +let jsonGen: ICodeGenerator = CodeGenerator(delegate: JSONGeneratorPhases()) + +htmlGen.crossCompile() +jsonGen.crossCompile() From df3dd8b1f022713ccb3b921c77f91f9d2756e30d Mon Sep 17 00:00:00 2001 From: David Orriss Jr Date: Sat, 17 Jun 2017 09:46:24 -0700 Subject: [PATCH 16/66] new example for the Template Pattern --- Design-Patterns.playground.zip | Bin 150074 -> 150512 bytes .../Contents.swift | 71 ++++++++++++++ .../Contents.swift | 12 +-- README.md | 89 ++++++++++++++++-- source/behavioral/template.swift | 5 +- 5 files changed, 163 insertions(+), 14 deletions(-) diff --git a/Design-Patterns.playground.zip b/Design-Patterns.playground.zip index adfa80d6a91403853dda93e4141a07754dfca17e..0175c35307379e3a8430bd13ed57600a17e049a1 100644 GIT binary patch delta 8710 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 delta 8306 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 zJn**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Strategy) */ /*: +🍪 Template +----------- + +The Template Pattern is used when two or more implementations of an +algorithm exist. The template is defined and then built upon with further +variations. Use this method when most (or all) subclasses need to implement +the same behavior. Traditionally, this would be accomplished with abstract +classes and protected methods (as in Java). However in Swift, because +abstract classes don't exist (yet - maybe someday), we need to accomplish +the behavior using interface delegation. + + +### Example +*/ + +protocol ICodeGenerator { + func crossCompile() +} + +protocol IGeneratorPhases { + func collectSource() + func crossCompile() +} + +class CodeGenerator : ICodeGenerator{ + var delegate: IGeneratorPhases + + init(delegate: IGeneratorPhases) { + self.delegate = delegate + } + + + //Template method + final func crossCompile() { + delegate.collectSource() + delegate.crossCompile() + } +} + +class HTMLGeneratorPhases : IGeneratorPhases { + func collectSource() { + print("HTMLGeneratorPhases collectSource() executed") + } + + func crossCompile() { + print("HTMLGeneratorPhases crossCompile() executed") + } +} + +class JSONGeneratorPhases : IGeneratorPhases { + func collectSource() { + print("JSONGeneratorPhases collectSource() executed") + } + + func crossCompile() { + print("JSONGeneratorPhases crossCompile() executed") + } +} + + + +/*: +### Usage +*/ + +let htmlGen : ICodeGenerator = CodeGenerator(delegate: HTMLGeneratorPhases()) +let jsonGen: ICodeGenerator = CodeGenerator(delegate: JSONGeneratorPhases()) + +htmlGen.crossCompile() +jsonGen.crossCompile() +/*: 🏃 Visitor ---------- diff --git a/Design-Patterns.playground/Pages/Structural.xcplaygroundpage/Contents.swift b/Design-Patterns.playground/Pages/Structural.xcplaygroundpage/Contents.swift index 1cecf7d..bc4f44b 100644 --- a/Design-Patterns.playground/Pages/Structural.xcplaygroundpage/Contents.swift +++ b/Design-Patterns.playground/Pages/Structural.xcplaygroundpage/Contents.swift @@ -126,9 +126,9 @@ Component protocol Shape { func draw(fillColor: String) } -/*: +/*: Leafs -*/ +*/ final class Square : Shape { func draw(fillColor: String) { print("Drawing a Square with color \(fillColor)") @@ -146,11 +146,11 @@ Composite */ final class Whiteboard : Shape { lazy var shapes = [Shape]() - + init(_ shapes:Shape...) { self.shapes = shapes } - + func draw(fillColor: String) { for shape in self.shapes { shape.draw(fillColor: fillColor) @@ -161,7 +161,7 @@ final class Whiteboard : Shape { ### Usage: */ var whiteboard = Whiteboard(Circle(), Square()) -whiteboard.draw("Red") +whiteboard.draw(fillColor: "Red") /*: 🍧 Decorator ------------ @@ -377,7 +377,7 @@ computer.open(doors: podBay) 🍬 Virtual Proxy ---------------- -The proxy pattern is used to provide a surrogate or placeholder object, which references an underlying object. +The proxy pattern is used to provide a surrogate or placeholder object, which references an underlying object. Virtual proxy is used for loading object on demand. ### Example diff --git a/README.md b/README.md index 07a39a0..57a3019 100644 --- a/README.md +++ b/README.md @@ -715,6 +715,83 @@ upper.print("O tempora, o mores!") ``` +🍪 Template +----------- + +The Template Pattern is used when two or more implementations of an +algorithm exist. The template is defined and then built upon with further +variations. Use this method when most (or all) subclasses need to implement +the same behavior. Traditionally, this would be accomplished with abstract +classes and protected methods (as in Java). However in Swift, because +abstract classes don't exist (yet - maybe someday), we need to accomplish +the behavior using interface delegation. + + +### Example + +```swift + + +protocol ICodeGenerator { + func crossCompile() +} + +protocol IGeneratorPhases { + func collectSource() + func crossCompile() +} + +class CodeGenerator : ICodeGenerator{ + var delegate: IGeneratorPhases + + init(delegate: IGeneratorPhases) { + self.delegate = delegate + } + + + //Template method + final func crossCompile() { + delegate.collectSource() + delegate.crossCompile() + } +} + +class HTMLGeneratorPhases : IGeneratorPhases { + func collectSource() { + print("HTMLGeneratorPhases collectSource() executed") + } + + func crossCompile() { + print("HTMLGeneratorPhases crossCompile() executed") + } +} + +class JSONGeneratorPhases : IGeneratorPhases { + func collectSource() { + print("JSONGeneratorPhases collectSource() executed") + } + + func crossCompile() { + print("JSONGeneratorPhases crossCompile() executed") + } +} + + + +``` + +### Usage + +```swift + + +let htmlGen : ICodeGenerator = CodeGenerator(delegate: HTMLGeneratorPhases()) +let jsonGen: ICodeGenerator = CodeGenerator(delegate: JSONGeneratorPhases()) + +htmlGen.crossCompile() +jsonGen.crossCompile() +``` + 🏃 Visitor ---------- @@ -1244,11 +1321,11 @@ protocol Shape { func draw(fillColor: String) } ``` - + Leafs ```swift - + final class Square : Shape { func draw(fillColor: String) { print("Drawing a Square with color \(fillColor)") @@ -1269,11 +1346,11 @@ Composite final class Whiteboard : Shape { lazy var shapes = [Shape]() - + init(_ shapes:Shape...) { self.shapes = shapes } - + func draw(fillColor: String) { for shape in self.shapes { shape.draw(fillColor: fillColor) @@ -1287,7 +1364,7 @@ final class Whiteboard : Shape { ```swift var whiteboard = Whiteboard(Circle(), Square()) -whiteboard.draw("Red") +whiteboard.draw(fillColor: "Red") ``` 🍧 Decorator @@ -1528,7 +1605,7 @@ computer.open(doors: podBay) 🍬 Virtual Proxy ---------------- -The proxy pattern is used to provide a surrogate or placeholder object, which references an underlying object. +The proxy pattern is used to provide a surrogate or placeholder object, which references an underlying object. Virtual proxy is used for loading object on demand. ### Example diff --git a/source/behavioral/template.swift b/source/behavioral/template.swift index 8a0188f..cf1f60c 100644 --- a/source/behavioral/template.swift +++ b/source/behavioral/template.swift @@ -6,8 +6,9 @@ The Template Pattern is used when two or more implementations of an algorithm exist. The template is defined and then built upon with further variations. Use this method when most (or all) subclasses need to implement the same behavior. Traditionally, this would be accomplished with abstract -classes (as in Java). However in Swift, because abstract classes don't yet -exist, we need to accomplish the behavior using interface delegation. +classes and protected methods (as in Java). However in Swift, because +abstract classes don't exist (yet - maybe someday), we need to accomplish +the behavior using interface delegation. ### Example From 90fd5bd157d93690615d5062aa84d6f67a1d1117 Mon Sep 17 00:00:00 2001 From: David Orriss Jr Date: Sat, 17 Jun 2017 10:28:22 -0700 Subject: [PATCH 17/66] adding a common implementation for completeness the whole idea of the Template Pattern is to show that you can have invocations that are common across the concrete implementations. so I added a sample --- Design-Patterns.playground.zip | Bin 150512 -> 150559 bytes .../Contents.swift | 6 ++++++ README.md | 6 ++++++ source/behavioral/template.swift | 6 ++++++ 4 files changed, 18 insertions(+) diff --git a/Design-Patterns.playground.zip b/Design-Patterns.playground.zip index 0175c35307379e3a8430bd13ed57600a17e049a1..7f4f2c5c999a8510ac3519c43a97a277ca6d7ffc 100644 GIT binary patch delta 4584 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 v4d}KoKmw_2fp?jt!smVgjJisWwrkU0A^Kl diff --git a/Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift b/Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift index eac4f85..ac109a9 100644 --- a/Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift +++ b/Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift @@ -646,12 +646,18 @@ class CodeGenerator : ICodeGenerator{ self.delegate = delegate } + private func fetchDataforGeneration(){ + //common implementation + print("fetchDataforGeneration invoked") + } //Template method final func crossCompile() { + fetchDataforGeneration() delegate.collectSource() delegate.crossCompile() } + } class HTMLGeneratorPhases : IGeneratorPhases { diff --git a/README.md b/README.md index 57a3019..26aa333 100644 --- a/README.md +++ b/README.md @@ -748,12 +748,18 @@ class CodeGenerator : ICodeGenerator{ self.delegate = delegate } + private func fetchDataforGeneration(){ + //common implementation + print("fetchDataforGeneration invoked") + } //Template method final func crossCompile() { + fetchDataforGeneration() delegate.collectSource() delegate.crossCompile() } + } class HTMLGeneratorPhases : IGeneratorPhases { diff --git a/source/behavioral/template.swift b/source/behavioral/template.swift index cf1f60c..f0300a0 100644 --- a/source/behavioral/template.swift +++ b/source/behavioral/template.swift @@ -30,12 +30,18 @@ class CodeGenerator : ICodeGenerator{ self.delegate = delegate } + private func fetchDataforGeneration(){ + //common implementation + print("fetchDataforGeneration invoked") + } //Template method final func crossCompile() { + fetchDataforGeneration() delegate.collectSource() delegate.crossCompile() } + } class HTMLGeneratorPhases : IGeneratorPhases { From 216eea1df7da793acfd384363de9a4a95e5b6f13 Mon Sep 17 00:00:00 2001 From: seongho Date: Thu, 15 Mar 2018 01:30:29 +0900 Subject: [PATCH 18/66] Memento Pattern - Change Keys type form struct to enum because we don't need to initialize Keys. - issue #79 --- Design-Patterns.playground.zip | Bin 150559 -> 156650 bytes .../Contents.swift | 2 +- README.md | 2 +- source/behavioral/memento.swift | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Design-Patterns.playground.zip b/Design-Patterns.playground.zip index 7f4f2c5c999a8510ac3519c43a97a277ca6d7ffc..99f0cee4efee6e37fe77c7672c062782a3c6ad62 100644 GIT binary patch delta 8542 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 diff --git a/Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift b/Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift index ac109a9..00ae08a 100644 --- a/Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift +++ b/Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift @@ -388,7 +388,7 @@ protocol MementoConvertible { struct GameState: MementoConvertible { - private struct Keys { + private enum Keys { static let chapter = "com.valve.halflife.chapter" static let weapon = "com.valve.halflife.weapon" } diff --git a/README.md b/README.md index 26aa333..5fc3d0d 100644 --- a/README.md +++ b/README.md @@ -454,7 +454,7 @@ protocol MementoConvertible { struct GameState: MementoConvertible { - private struct Keys { + private enum Keys { static let chapter = "com.valve.halflife.chapter" static let weapon = "com.valve.halflife.weapon" } diff --git a/source/behavioral/memento.swift b/source/behavioral/memento.swift index b38a577..cbf9c93 100644 --- a/source/behavioral/memento.swift +++ b/source/behavioral/memento.swift @@ -17,7 +17,7 @@ protocol MementoConvertible { struct GameState: MementoConvertible { - private struct Keys { + private enum Keys { static let chapter = "com.valve.halflife.chapter" static let weapon = "com.valve.halflife.weapon" } From 41593c882e5309de7b721dbc43bd049ed912ffbd Mon Sep 17 00:00:00 2001 From: Oktawian Chojnacki Date: Fri, 5 Apr 2019 19:57:17 +0300 Subject: [PATCH 19/66] [Swift5] Massive update --- .gitignore | 10 +- Design-Patterns.playground.zip | Bin 156650 -> 159940 bytes .../Contents.swift | 263 +++---- .../Contents.swift | 164 ++-- .../Index.xcplaygroundpage/Contents.swift | 21 + .../Contents.swift | 233 +++--- .../timeline.xctimeline | 6 + .../contents.xcplayground | 1 + .../contents.xcworkspacedata | 7 - .../xcshareddata/Design-Patterns.xccheckout | 41 - GENERATE.md | 5 +- .../Contents.swift | 7 + .../Contents.swift | 3 + .../timeline.xctimeline | 6 + MyPlayground.playground/contents.xcplayground | 4 + PULL_REQUEST_TEMPLATE.md | 8 +- README.md | 735 +++++++----------- generate-playground.sh | 71 +- source/Index/header.md | 9 + source/Index/welcome.swift | 2 + .../behavioral/chain_of_responsibility.swift | 61 +- source/behavioral/command.swift | 6 +- source/behavioral/{_title.swift => header.md} | 8 +- source/behavioral/interpreter.swift | 3 - source/behavioral/mediator.swift | 4 +- source/behavioral/memento.swift | 20 +- source/behavioral/observer.swift | 3 - source/behavioral/state.swift | 4 - source/behavioral/strategy.swift | 61 +- source/behavioral/template.swift | 77 -- source/behavioral/visitor.swift | 24 +- source/contents.md | 6 + source/creational/abstract_factory.swift | 71 +- source/creational/builder.swift | 5 +- source/creational/factory.swift | 37 +- source/creational/{_title.swift => header.md} | 8 +- source/creational/prototype.swift | 32 +- source/creational/singleton.swift | 7 +- source/endComment | 2 + source/endSwiftCode | 2 + source/{footer.swift => footer.md} | 3 - source/header.swift | 16 - source/imports.swift | 2 + source/startComment | 1 + source/startSwiftCode | 3 + source/structural/adapter.swift | 40 +- source/structural/bridge.swift | 12 +- source/structural/composite.swift | 14 +- source/structural/decorator.swift | 77 +- source/structural/facade.swift | 31 +- source/structural/flyweight.swift | 34 +- source/structural/{_title.swift => header.md} | 8 +- source/structural/protection_proxy.swift | 8 +- source/structural/virtual_proxy.swift | 5 +- 54 files changed, 951 insertions(+), 1340 deletions(-) create mode 100644 Design-Patterns.playground/Pages/Index.xcplaygroundpage/Contents.swift create mode 100644 Design-Patterns.playground/Pages/Structural.xcplaygroundpage/timeline.xctimeline delete mode 100644 Design-Patterns.playground/playground.xcworkspace/contents.xcworkspacedata delete mode 100644 Design-Patterns.playground/playground.xcworkspace/xcshareddata/Design-Patterns.xccheckout create mode 100644 MyPlayground.playground/Pages/Untitled Page 2.xcplaygroundpage/Contents.swift create mode 100644 MyPlayground.playground/Pages/Untitled Page.xcplaygroundpage/Contents.swift create mode 100644 MyPlayground.playground/Pages/Untitled Page.xcplaygroundpage/timeline.xctimeline create mode 100644 MyPlayground.playground/contents.xcplayground create mode 100644 source/Index/header.md create mode 100644 source/Index/welcome.swift rename source/behavioral/{_title.swift => header.md} (75%) delete mode 100644 source/behavioral/template.swift create mode 100644 source/contents.md rename source/creational/{_title.swift => header.md} (80%) create mode 100644 source/endComment create mode 100644 source/endSwiftCode rename source/{footer.swift => footer.md} (94%) delete mode 100644 source/header.swift create mode 100644 source/imports.swift create mode 100644 source/startComment create mode 100644 source/startSwiftCode rename source/structural/{_title.swift => header.md} (69%) diff --git a/.gitignore b/.gitignore index 8cdb2b6..ae30dd1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,4 @@ -# CocoaPods -# -# We recommend against adding the Pods directory to your .gitignore. However -# you should judge for yourself, the pros and cons are mentioned at: -# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control? -# -# Pods/ - .DS_Store UserInterfaceState.xcuserstate +playground.xcworkspace +xcuserdata \ No newline at end of file diff --git a/Design-Patterns.playground.zip b/Design-Patterns.playground.zip index 99f0cee4efee6e37fe77c7672c062782a3c6ad62..ec7eebe29e14dff586d70a44e13c57ebeace4339 100644 GIT binary patch delta 23410 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 Ay#N3J delta 20271 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 Nwa{SL?14Tv{2w<^?=JuV diff --git a/Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift b/Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift index 00ae08a..898a6db 100644 --- a/Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift +++ b/Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift @@ -1,15 +1,19 @@ -//: Behavioral | -//: [Creational](Creational) | -//: [Structural](Structural) /*: + Behavioral ========== >In software engineering, behavioral design patterns are design patterns that identify common communication patterns between objects and realize these patterns. By doing so, these patterns increase flexibility in carrying out this communication. > >**Source:** [wikipedia.org](http://en.wikipedia.org/wiki/Behavioral_pattern) + +## Table of Contents + +* [Behavioral](Behavioral) +* [Creational](Creational) +* [Structural](Structural) + */ -import Swift import Foundation /*: 🐝 Chain Of Responsibility @@ -19,19 +23,24 @@ The chain of responsibility pattern is used to process varied requests, each of ### Example: */ -final class MoneyPile { + +protocol Withdrawing { + func withdraw(amount: Int) -> Bool +} + +final class MoneyPile: Withdrawing { let value: Int var quantity: Int - var nextPile: MoneyPile? + var next: Withdrawing? - init(value: Int, quantity: Int, nextPile: MoneyPile?) { + init(value: Int, quantity: Int, next: Withdrawing?) { self.value = value self.quantity = quantity - self.nextPile = nextPile + self.next = next } - func canWithdraw(amount: Int) -> Bool { + func withdraw(amount: Int) -> Bool { var amount = amount @@ -55,28 +64,29 @@ final class MoneyPile { return true } - if let next = self.nextPile { - return next.canWithdraw(amount: amount) + if let next = self.next { + return next.withdraw(amount: amount) } return false } } -final class ATM { - private var hundred: MoneyPile - private var fifty: MoneyPile - private var twenty: MoneyPile - private var ten: MoneyPile +final class ATM: Withdrawing { - private var startPile: MoneyPile { + private var hundred: Withdrawing + private var fifty: Withdrawing + private var twenty: Withdrawing + private var ten: Withdrawing + + private var startPile: Withdrawing { return self.hundred } - init(hundred: MoneyPile, - fifty: MoneyPile, - twenty: MoneyPile, - ten: MoneyPile) { + init(hundred: Withdrawing, + fifty: Withdrawing, + twenty: Withdrawing, + ten: Withdrawing) { self.hundred = hundred self.fifty = fifty @@ -84,28 +94,23 @@ final class ATM { self.ten = ten } - func canWithdraw(amount: Int) -> String { - return "Can withdraw: \(self.startPile.canWithdraw(amount: amount))" + func withdraw(amount: Int) -> Bool { + return startPile.withdraw(amount: amount) } } /*: ### Usage */ // Create piles of money and link them together 10 < 20 < 50 < 100.** -let ten = MoneyPile(value: 10, quantity: 6, nextPile: nil) -let twenty = MoneyPile(value: 20, quantity: 2, nextPile: ten) -let fifty = MoneyPile(value: 50, quantity: 2, nextPile: twenty) -let hundred = MoneyPile(value: 100, quantity: 1, nextPile: fifty) +let ten = MoneyPile(value: 10, quantity: 6, next: nil) +let twenty = MoneyPile(value: 20, quantity: 2, next: ten) +let fifty = MoneyPile(value: 50, quantity: 2, next: twenty) +let hundred = MoneyPile(value: 100, quantity: 1, next: fifty) // Build ATM. var atm = ATM(hundred: hundred, fifty: fifty, twenty: twenty, ten: ten) -atm.canWithdraw(amount: 310) // Cannot because ATM has only 300 -atm.canWithdraw(amount: 100) // Can withdraw - 1x100 -atm.canWithdraw(amount: 165) // Cannot withdraw because ATM doesn't has bill with value of 5 -atm.canWithdraw(amount: 30) // Can withdraw - 1x20, 2x10 -/*: ->**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Chain-Of-Responsibility) -*/ +atm.withdraw(amount: 310) // Cannot because ATM has only 300 +atm.withdraw(amount: 100) // Can withdraw - 1x100 /*: 👫 Command ---------- @@ -118,7 +123,7 @@ protocol DoorCommand { func execute() -> String } -class OpenCommand : DoorCommand { +final class OpenCommand: DoorCommand { let doors:String required init(doors: String) { @@ -130,7 +135,7 @@ class OpenCommand : DoorCommand { } } -class CloseCommand : DoorCommand { +final class CloseCommand: DoorCommand { let doors:String required init(doors: String) { @@ -142,7 +147,7 @@ class CloseCommand : DoorCommand { } } -class HAL9000DoorsOperations { +final class HAL9000DoorsOperations { let openCommand: DoorCommand let closeCommand: DoorCommand @@ -257,9 +262,6 @@ context.assign(expression: c, value: 3) var result = expression.evaluate(context) /*: ->**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Interpreter) -*/ -/*: 🍫 Iterator ----------- @@ -366,9 +368,7 @@ messagesMediator.add(recipient: user0) messagesMediator.add(recipient: user1) spamMonster(message: "I'd Like to Add you to My Professional Network", worker: messagesMediator) -/*: ->**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Mediator) -*/ + /*: 💾 Memento ---------- @@ -377,7 +377,7 @@ The memento pattern is used to capture the current state of an object and store ### Example */ -typealias Memento = NSDictionary +typealias Memento = [String: String] /*: Originator */ @@ -402,8 +402,8 @@ struct GameState: MementoConvertible { } init?(memento: Memento) { - guard let mementoChapter = memento[Keys.chapter] as? String, - let mementoWeapon = memento[Keys.weapon] as? String else { + guard let mementoChapter = memento[Keys.chapter], + let mementoWeapon = memento[Keys.weapon] else { return nil } @@ -419,20 +419,20 @@ struct GameState: MementoConvertible { Caretaker */ enum CheckPoint { + + private static let defaults = UserDefaults.standard + static func save(_ state: MementoConvertible, saveName: String) { - let defaults = UserDefaults.standard defaults.set(state.memento, forKey: saveName) defaults.synchronize() } - static func restore(saveName: String) -> Memento? { - let defaults = UserDefaults.standard - - return defaults.object(forKey: saveName) as? Memento + static func restore(saveName: String) -> Any? { + return defaults.object(forKey: saveName) } } /*: - ### Usage +### Usage */ var gameState = GameState(chapter: "Black Mesa Inbound", weapon: "Crowbar") @@ -448,7 +448,7 @@ gameState.chapter = "Office Complex" gameState.weapon = "Crossbow" CheckPoint.save(gameState, saveName: "gameState3") -if let memento = CheckPoint.restore(saveName: "gameState1") { +if let memento = CheckPoint.restore(saveName: "gameState1") as? Memento { let finalState = GameState(memento: memento) dump(finalState) } @@ -503,9 +503,6 @@ var testChambers = TestChambers() testChambers.observer = observerInstance testChambers.testChamberNumber += 1 /*: ->**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Observer) -*/ -/*: 🐉 State --------- @@ -532,7 +529,6 @@ final class Context { func changeStateToUnauthorized() { state = UnauthorizedState() } - } protocol State { @@ -565,9 +561,6 @@ userContext.changeStateToAuthorized(userId: "admin") userContext.changeStateToUnauthorized() (userContext.isAuthorized, userContext.userId) /*: ->**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-State) -*/ -/*: 💡 Strategy ----------- @@ -575,122 +568,56 @@ The strategy pattern is used to create an interchangeable family of algorithms f ### Example */ -protocol PrintStrategy { - func print(_ string: String) -> String -} - -final class Printer { - private let strategy: PrintStrategy - - func print(_ string: String) -> String { - return self.strategy.print(string) - } - - init(strategy: PrintStrategy) { - self.strategy = strategy - } +struct TestSubject { + let pupilDiameter: Double + let blushResponse: Double + let isOrganic: Bool } -final class UpperCaseStrategy: PrintStrategy { - func print(_ string: String) -> String { - return string.uppercased() - } +protocol RealnessTesting: AnyObject { + func testRealness(_ testSubject: TestSubject) -> Bool } -final class LowerCaseStrategy: PrintStrategy { - func print(_ string:String) -> String { - return string.lowercased() +final class VoightKampffTest: RealnessTesting { + func testRealness(_ testSubject: TestSubject) -> Bool { + return testSubject.pupilDiameter < 30.0 || testSubject.blushResponse == 0.0 } } -/*: -### Usage -*/ -var lower = Printer(strategy: LowerCaseStrategy()) -lower.print("O tempora, o mores!") - -var upper = Printer(strategy: UpperCaseStrategy()) -upper.print("O tempora, o mores!") -/*: ->**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Strategy) -*/ -/*: -🍪 Template ------------ - -The Template Pattern is used when two or more implementations of an -algorithm exist. The template is defined and then built upon with further -variations. Use this method when most (or all) subclasses need to implement -the same behavior. Traditionally, this would be accomplished with abstract -classes and protected methods (as in Java). However in Swift, because -abstract classes don't exist (yet - maybe someday), we need to accomplish -the behavior using interface delegation. - - -### Example -*/ - -protocol ICodeGenerator { - func crossCompile() -} - -protocol IGeneratorPhases { - func collectSource() - func crossCompile() -} -class CodeGenerator : ICodeGenerator{ - var delegate: IGeneratorPhases - - init(delegate: IGeneratorPhases) { - self.delegate = delegate - } - - private func fetchDataforGeneration(){ - //common implementation - print("fetchDataforGeneration invoked") +final class GeneticTest: RealnessTesting { + func testRealness(_ testSubject: TestSubject) -> Bool { + return testSubject.isOrganic } - - //Template method - final func crossCompile() { - fetchDataforGeneration() - delegate.collectSource() - delegate.crossCompile() - } - } -class HTMLGeneratorPhases : IGeneratorPhases { - func collectSource() { - print("HTMLGeneratorPhases collectSource() executed") - } +final class BladeRunner { + private let strategy: RealnessTesting - func crossCompile() { - print("HTMLGeneratorPhases crossCompile() executed") + init(test: RealnessTesting) { + self.strategy = test } -} -class JSONGeneratorPhases : IGeneratorPhases { - func collectSource() { - print("JSONGeneratorPhases collectSource() executed") - } - - func crossCompile() { - print("JSONGeneratorPhases crossCompile() executed") + func testIfAndroid(_ testSubject: TestSubject) -> Bool { + return !strategy.testRealness(testSubject) } } - - /*: -### Usage -*/ + ### Usage + */ -let htmlGen : ICodeGenerator = CodeGenerator(delegate: HTMLGeneratorPhases()) -let jsonGen: ICodeGenerator = CodeGenerator(delegate: JSONGeneratorPhases()) +let rachel = TestSubject(pupilDiameter: 30.2, + blushResponse: 0.3, + isOrganic: false) -htmlGen.crossCompile() -jsonGen.crossCompile() +// Deckard is using a traditional test +let deckard = BladeRunner(test: VoightKampffTest()) +let isRachelAndroid = deckard.testIfAndroid(rachel) + +// Gaff is using a very precise method +let gaff = BladeRunner(test: GeneticTest()) +let isDeckardAndroid = gaff.testIfAndroid(rachel) /*: 🏃 Visitor ---------- @@ -703,52 +630,48 @@ protocol PlanetVisitor { func visit(planet: PlanetAlderaan) func visit(planet: PlanetCoruscant) func visit(planet: PlanetTatooine) - func visit(planet: MoonJedah) + func visit(planet: MoonJedha) } protocol Planet { func accept(visitor: PlanetVisitor) } -class MoonJedah: Planet { +final class MoonJedha: Planet { func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) } } -class PlanetAlderaan: Planet { +final class PlanetAlderaan: Planet { func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) } } -class PlanetCoruscant: Planet { +final class PlanetCoruscant: Planet { func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) } } -class PlanetTatooine: Planet { +final class PlanetTatooine: Planet { func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) } } - - -class NameVisitor: PlanetVisitor { +final class NameVisitor: PlanetVisitor { var name = "" func visit(planet: PlanetAlderaan) { name = "Alderaan" } func visit(planet: PlanetCoruscant) { name = "Coruscant" } func visit(planet: PlanetTatooine) { name = "Tatooine" } - func visit(planet: MoonJedah) { name = "Jedah" } + func visit(planet: MoonJedha) { name = "Jedha" } } /*: ### Usage */ -let planets: [Planet] = [PlanetAlderaan(), PlanetCoruscant(), PlanetTatooine(), MoonJedah()] +let planets: [Planet] = [PlanetAlderaan(), PlanetCoruscant(), PlanetTatooine(), MoonJedha()] let names = planets.map { (planet: Planet) -> String in let visitor = NameVisitor() planet.accept(visitor: visitor) - return visitor.name + + return visitor.name } names -/*: ->**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Visitor) -*/ diff --git a/Design-Patterns.playground/Pages/Creational.xcplaygroundpage/Contents.swift b/Design-Patterns.playground/Pages/Creational.xcplaygroundpage/Contents.swift index bbdd2ed..6b46311 100644 --- a/Design-Patterns.playground/Pages/Creational.xcplaygroundpage/Contents.swift +++ b/Design-Patterns.playground/Pages/Creational.xcplaygroundpage/Contents.swift @@ -1,15 +1,19 @@ -//: [Behavioral](Behavioral) | -//: Creational | -//: [Structural](Structural) /*: + Creational ========== > In software engineering, creational design patterns are design patterns that deal with object creation mechanisms, trying to create objects in a manner suitable to the situation. The basic form of object creation could result in design problems or added complexity to the design. Creational design patterns solve this problem by somehow controlling this object creation. > >**Source:** [wikipedia.org](http://en.wikipedia.org/wiki/Creational_pattern) + +## Table of Contents + +* [Behavioral](Behavioral) +* [Creational](Creational) +* [Structural](Structural) + */ -import Swift import Foundation /*: 🌰 Abstract Factory @@ -19,68 +23,59 @@ The abstract factory pattern is used to provide a client with a set of related o The "family" of objects created by the factory are determined at run-time. ### Example -*/ -/*: + Protocols */ -protocol Decimal { - func stringValue() -> String - // factory - static func make(string : String) -> Decimal + +protocol BurgerDescribing { + var ingredients: [String] { get } } -typealias NumberFactory = (String) -> Decimal +struct CheeseBurger: BurgerDescribing { + let ingredients: [String] +} -// Number implementations with factory methods +protocol BurgerMaking { + func make() -> BurgerDescribing +} -struct NextStepNumber: Decimal { - private var nextStepNumber: NSNumber +// Number implementations with factory methods - func stringValue() -> String { return nextStepNumber.stringValue } - - // factory - static func make(string: String) -> Decimal { - return NextStepNumber(nextStepNumber: NSNumber(value: (string as NSString).longLongValue)) +final class BigKahunaBurger: BurgerMaking { + func make() -> BurgerDescribing { + return CheeseBurger(ingredients: ["Cheese", "Burger", "Lettuce", "Tomato"]) } } -struct SwiftNumber : Decimal { - private var swiftInt: Int - - func stringValue() -> String { return "\(swiftInt)" } - - // factory - static func make(string: String) -> Decimal { - return SwiftNumber(swiftInt:(string as NSString).integerValue) +final class JackInTheBox: BurgerMaking { + func make() -> BurgerDescribing { + return CheeseBurger(ingredients: ["Cheese", "Burger", "Tomato", "Onions"]) } } + /*: Abstract factory */ -enum NumberType { - case nextStep, swift -} -enum NumberHelper { - static func factory(for type: NumberType) -> NumberFactory { - switch type { - case .nextStep: - return NextStepNumber.make - case .swift: - return SwiftNumber.make +enum BurgerFactoryType: BurgerMaking { + + case bigKahuna + case jackInTheBox + + func make() -> BurgerDescribing { + switch self { + case .bigKahuna: + return BigKahunaBurger().make() + case .jackInTheBox: + return JackInTheBox().make() } } } /*: ### Usage */ -let factoryOne = NumberHelper.factory(for: .nextStep) -let numberOne = factoryOne("1") -numberOne.stringValue() - -let factoryTwo = NumberHelper.factory(for: .swift) -let numberTwo = factoryTwo("2") -numberTwo.stringValue() +let bigKahuna = BurgerFactoryType.bigKahuna.make() +let jackInTheBox = BurgerFactoryType.jackInTheBox.make() /*: 👷 Builder ---------- @@ -90,7 +85,7 @@ An external class controls the construction algorithm. ### Example */ -class DeathStarBuilder { +final class DeathStarBuilder { var x: Double? var y: Double? @@ -135,9 +130,6 @@ let empire = DeathStarBuilder { builder in let deathStar = DeathStar(builder:empire) /*: ->**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Builder) -*/ -/*: 🏭 Factory Method ----------------- @@ -145,42 +137,45 @@ The factory pattern is used to replace class constructors, abstracting the proce ### Example */ -protocol Currency { - func symbol() -> String - func code() -> String +protocol CurrencyDescribing { + var symbol: String { get } + var code: String { get } } -class Euro : Currency { - func symbol() -> String { +final class Euro: CurrencyDescribing { + var symbol: String { return "€" } - func code() -> String { + var code: String { return "EUR" } } -class UnitedStatesDolar : Currency { - func symbol() -> String { +final class UnitedStatesDolar: CurrencyDescribing { + var symbol: String { return "$" } - func code() -> String { + var code: String { return "USD" } } enum Country { - case unitedStates, spain, uk, greece + case unitedStates + case spain + case uk + case greece } enum CurrencyFactory { - static func currency(for country:Country) -> Currency? { + static func currency(for country: Country) -> CurrencyDescribing? { switch country { - case .spain, .greece : + case .spain, .greece: return Euro() - case .unitedStates : + case .unitedStates: return UnitedStatesDolar() default: return nil @@ -193,10 +188,10 @@ enum CurrencyFactory { */ let noCurrencyCode = "No Currency Code Available" -CurrencyFactory.currency(for: .greece)?.code() ?? noCurrencyCode -CurrencyFactory.currency(for: .spain)?.code() ?? noCurrencyCode -CurrencyFactory.currency(for: .unitedStates)?.code() ?? noCurrencyCode -CurrencyFactory.currency(for: .uk)?.code() ?? noCurrencyCode +CurrencyFactory.currency(for: .greece)?.code ?? noCurrencyCode +CurrencyFactory.currency(for: .spain)?.code ?? noCurrencyCode +CurrencyFactory.currency(for: .unitedStates)?.code ?? noCurrencyCode +CurrencyFactory.currency(for: .uk)?.code ?? noCurrencyCode /*: 🃏 Prototype ------------ @@ -206,34 +201,32 @@ This practise is particularly useful when the construction of a new object is in ### Example */ -class ChungasRevengeDisplay { - var name: String? - let font: String +struct MoonWorker { + + let name: String + var health: Int = 100 - init(font: String) { - self.font = font + init(name: String) { + self.name = name } - func clone() -> ChungasRevengeDisplay { - return ChungasRevengeDisplay(font:self.font) + func clone() -> MoonWorker { + return MoonWorker(name: name) } } /*: ### Usage */ -let Prototype = ChungasRevengeDisplay(font:"GotanProject") +let prototype = MoonWorker(name: "Sam Bell") -let Philippe = Prototype.clone() -Philippe.name = "Philippe" +var bell1 = prototype.clone() +bell1.health = 12 -let Christoph = Prototype.clone() -Christoph.name = "Christoph" +var bell2 = prototype.clone() +bell2.health = 23 -let Eduardo = Prototype.clone() -Eduardo.name = "Eduardo" -/*: ->**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Prototype) -*/ +var bell3 = prototype.clone() +bell3.health = 0 /*: 💍 Singleton ------------ @@ -244,8 +237,9 @@ There are very few applications, do not overuse this pattern! ### Example: */ -class DeathStarSuperlaser { - static let sharedInstance = DeathStarSuperlaser() +final class ElonMusk { + + static let shared = ElonMusk() private init() { // Private initialization to ensure just one instance is created. @@ -254,4 +248,4 @@ class DeathStarSuperlaser { /*: ### Usage: */ -let laser = DeathStarSuperlaser.sharedInstance +let elon = ElonMusk.shared // There is only one Elon Musk folks. diff --git a/Design-Patterns.playground/Pages/Index.xcplaygroundpage/Contents.swift b/Design-Patterns.playground/Pages/Index.xcplaygroundpage/Contents.swift new file mode 100644 index 0000000..4a54f9f --- /dev/null +++ b/Design-Patterns.playground/Pages/Index.xcplaygroundpage/Contents.swift @@ -0,0 +1,21 @@ +/*: + +Design Patterns implemented in Swift 5.0 +======================================== + +A short cheat-sheet with Xcode 10.2 Playground ([Design-Patterns.playground.zip](https://raw.githubusercontent.com/ochococo/Design-Patterns-In-Swift/master/Design-Patterns.playground.zip)). + +👷 Project maintained by: [@nsmeme](http://twitter.com/nsmeme) (Oktawian Chojnacki) + +🚀 How to generate README, Playground and zip from source: [GENERATE.md](https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/GENERATE.md) + +## Table of Contents + +* [Behavioral](Behavioral) +* [Creational](Creational) +* [Structural](Structural) + +*/ +import Foundation + +print("Welcome!") diff --git a/Design-Patterns.playground/Pages/Structural.xcplaygroundpage/Contents.swift b/Design-Patterns.playground/Pages/Structural.xcplaygroundpage/Contents.swift index bc4f44b..29c0ef1 100644 --- a/Design-Patterns.playground/Pages/Structural.xcplaygroundpage/Contents.swift +++ b/Design-Patterns.playground/Pages/Structural.xcplaygroundpage/Contents.swift @@ -1,15 +1,19 @@ -//: [Behavioral](Behavioral) | -//: [Creational](Creational) | -//: Structural /*: + Structural ========== >In software engineering, structural design patterns are design patterns that ease the design by identifying a simple way to realize relationships between entities. > >**Source:** [wikipedia.org](http://en.wikipedia.org/wiki/Structural_pattern) + +## Table of Contents + +* [Behavioral](Behavioral) +* [Creational](Creational) +* [Structural](Structural) + */ -import Swift import Foundation /*: 🔌 Adapter @@ -19,18 +23,18 @@ The adapter pattern is used to provide a link between two otherwise incompatible ### Example */ -protocol OlderDeathStarSuperLaserAiming { - var angleV: NSNumber {get} - var angleH: NSNumber {get} +protocol NewDeathStarSuperLaserAiming { + var angleV: Double { get } + var angleH: Double { get } } /*: **Adaptee** */ -struct DeathStarSuperlaserTarget { - let angleHorizontal: Double - let angleVertical: Double +struct OldDeathStarSuperlaserTarget { + let angleHorizontal: Float + let angleVertical: Float - init(angleHorizontal:Double, angleVertical:Double) { + init(angleHorizontal: Float, angleVertical: Float) { self.angleHorizontal = angleHorizontal self.angleVertical = angleVertical } @@ -38,32 +42,30 @@ struct DeathStarSuperlaserTarget { /*: **Adapter** */ -struct OldDeathStarSuperlaserTarget : OlderDeathStarSuperLaserAiming { - private let target : DeathStarSuperlaserTarget +struct NewDeathStarSuperlaserTarget: NewDeathStarSuperLaserAiming { + + private let target: OldDeathStarSuperlaserTarget - var angleV:NSNumber { - return NSNumber(value: target.angleVertical) + var angleV: Double { + return Double(target.angleVertical) } - var angleH:NSNumber { - return NSNumber(value: target.angleHorizontal) + var angleH: Double { + return Double(target.angleHorizontal) } - init(_ target:DeathStarSuperlaserTarget) { + init(_ target: OldDeathStarSuperlaserTarget) { self.target = target } } /*: ### Usage */ -let target = DeathStarSuperlaserTarget(angleHorizontal: 14.0, angleVertical: 12.0) -let oldFormat = OldDeathStarSuperlaserTarget(target) +let target = OldDeathStarSuperlaserTarget(angleHorizontal: 14.0, angleVertical: 12.0) +let newFormat = NewDeathStarSuperlaserTarget(target) -oldFormat.angleH -oldFormat.angleV -/*: ->**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Adapter) -*/ +newFormat.angleH +newFormat.angleV /*: 🌉 Bridge ---------- @@ -73,7 +75,7 @@ The bridge pattern is used to separate the abstract elements of a class from the ### Example */ protocol Switch { - var appliance: Appliance {get set} + var appliance: Appliance { get set } func turnOn() } @@ -81,7 +83,7 @@ protocol Appliance { func run() } -class RemoteControl: Switch { +final class RemoteControl: Switch { var appliance: Appliance func turnOn() { @@ -93,13 +95,13 @@ class RemoteControl: Switch { } } -class TV: Appliance { +final class TV: Appliance { func run() { print("tv turned on"); } } -class VacuumCleaner: Appliance { +final class VacuumCleaner: Appliance { func run() { print("vacuum cleaner turned on") } @@ -107,10 +109,10 @@ class VacuumCleaner: Appliance { /*: ### Usage */ -var tvRemoteControl = RemoteControl(appliance: TV()) +let tvRemoteControl = RemoteControl(appliance: TV()) tvRemoteControl.turnOn() -var fancyVacuumCleanerRemoteControl = RemoteControl(appliance: VacuumCleaner()) +let fancyVacuumCleanerRemoteControl = RemoteControl(appliance: VacuumCleaner()) fancyVacuumCleanerRemoteControl.turnOn() /*: 🌿 Composite @@ -119,8 +121,7 @@ fancyVacuumCleanerRemoteControl.turnOn() The composite pattern is used to create hierarchical, recursive tree structures of related objects where any element of the structure may be accessed and utilised in a standard manner. ### Example -*/ -/*: + Component */ protocol Shape { @@ -129,13 +130,13 @@ protocol Shape { /*: Leafs */ -final class Square : Shape { +final class Square: Shape { func draw(fillColor: String) { print("Drawing a Square with color \(fillColor)") } } -final class Circle : Shape { +final class Circle: Shape { func draw(fillColor: String) { print("Drawing a circle with color \(fillColor)") } @@ -144,10 +145,11 @@ final class Circle : Shape { /*: Composite */ -final class Whiteboard : Shape { - lazy var shapes = [Shape]() +final class Whiteboard: Shape { - init(_ shapes:Shape...) { + private lazy var shapes = [Shape]() + + init(_ shapes: Shape...) { self.shapes = shapes } @@ -171,74 +173,59 @@ This provides a flexible alternative to using inheritance to modify behaviour. ### Example */ -protocol Coffee { - func getCost() -> Double - func getIngredients() -> String +protocol CostHaving { + var cost: Double { get } } -class SimpleCoffee: Coffee { - func getCost() -> Double { - return 1.0 - } - - func getIngredients() -> String { - return "Coffee" - } +protocol IngredientsHaving { + var ingredients: [String] { get } } -class CoffeeDecorator: Coffee { - private let decoratedCoffee: Coffee - fileprivate let ingredientSeparator: String = ", " - - required init(decoratedCoffee: Coffee) { - self.decoratedCoffee = decoratedCoffee - } +typealias BeverageDataHaving = CostHaving & IngredientsHaving - func getCost() -> Double { - return decoratedCoffee.getCost() - } +struct SimpleCoffee: BeverageDataHaving { + let cost: Double = 1.0 + let ingredients = ["Water", "Coffee"] +} - func getIngredients() -> String { - return decoratedCoffee.getIngredients() - } +protocol BeverageHaving: BeverageDataHaving { + var beverage: BeverageDataHaving { get } } -final class Milk: CoffeeDecorator { - required init(decoratedCoffee: Coffee) { - super.init(decoratedCoffee: decoratedCoffee) - } +struct Milk: BeverageHaving { - override func getCost() -> Double { - return super.getCost() + 0.5 + let beverage: BeverageDataHaving + + var cost: Double { + return beverage.cost + 0.5 } - override func getIngredients() -> String { - return super.getIngredients() + ingredientSeparator + "Milk" + var ingredients: [String] { + return beverage.ingredients + ["Milk"] } } -final class WhipCoffee: CoffeeDecorator { - required init(decoratedCoffee: Coffee) { - super.init(decoratedCoffee: decoratedCoffee) - } +struct WhipCoffee: BeverageHaving { + + let beverage: BeverageDataHaving - override func getCost() -> Double { - return super.getCost() + 0.7 + var cost: Double { + return beverage.cost + 0.5 } - override func getIngredients() -> String { - return super.getIngredients() + ingredientSeparator + "Whip" + var ingredients: [String] { + return beverage.ingredients + ["Whip"] } } /*: ### Usage: */ -var someCoffee: Coffee = SimpleCoffee() -print("Cost : \(someCoffee.getCost()); Ingredients: \(someCoffee.getIngredients())") -someCoffee = Milk(decoratedCoffee: someCoffee) -print("Cost : \(someCoffee.getCost()); Ingredients: \(someCoffee.getIngredients())") -someCoffee = WhipCoffee(decoratedCoffee: someCoffee) -print("Cost : \(someCoffee.getCost()); Ingredients: \(someCoffee.getIngredients())") +var someCoffee: BeverageDataHaving = SimpleCoffee() +print("Cost: \(someCoffee.cost); Ingredients: \(someCoffee.ingredients)") +someCoffee = Milk(beverage: someCoffee) +print("Cost: \(someCoffee.cost); Ingredients: \(someCoffee.ingredients)") +someCoffee = WhipCoffee(beverage: someCoffee) +print("Cost: \(someCoffee.cost); Ingredients: \(someCoffee.ingredients)") /*: 🎁 Façade --------- @@ -247,49 +234,54 @@ The facade pattern is used to define a simplified interface to a more complex su ### Example */ -enum Eternal { +final class Defaults { - static func set(_ object: Any, forKey defaultName: String) { - let defaults: UserDefaults = UserDefaults.standard - defaults.set(object, forKey:defaultName) - defaults.synchronize() - } + private let defaults: UserDefaults - static func object(forKey key: String) -> AnyObject! { - let defaults: UserDefaults = UserDefaults.standard - return defaults.object(forKey: key) as AnyObject! + init(defaults: UserDefaults = .standard) { + self.defaults = defaults } + subscript(key: String) -> String? { + get { + return defaults.string(forKey: key) + } + + set { + defaults.set(newValue, forKey: key) + } + } } /*: ### Usage */ -Eternal.set("Disconnect me. I’d rather be nothing", forKey:"Bishop") -Eternal.object(forKey: "Bishop") +let storage = Defaults() + +// Store +storage["Bishop"] = "Disconnect me. I’d rather be nothing" + +// Read +storage["Bishop"] /*: ## 🍃 Flyweight The flyweight pattern is used to minimize memory usage or computational expenses by sharing as much as possible with other similar objects. ### Example */ -// Instances of CoffeeFlavour will be the Flyweights -final class SpecialityCoffee: CustomStringConvertible { - var origin: String - var description: String { - get { - return origin - } - } +// Instances of SpecialityCoffee will be the Flyweights +struct SpecialityCoffee { + let origin: String +} - init(origin: String) { - self.origin = origin - } +protocol CoffeeSearching { + func search(origin: String) -> SpecialityCoffee? } -// Menu acts as a factory and cache for CoffeeFlavour flyweight objects -final class Menu { +// Menu acts as a factory and cache for SpecialityCoffee flyweight objects +final class Menu: CoffeeSearching { + private var coffeeAvailable: [String: SpecialityCoffee] = [:] - func lookup(origin: String) -> SpecialityCoffee? { + func search(origin: String) -> SpecialityCoffee? { if coffeeAvailable.index(forKey: origin) == nil { coffeeAvailable[origin] = SpecialityCoffee(origin: origin) } @@ -300,10 +292,14 @@ final class Menu { final class CoffeeShop { private var orders: [Int: SpecialityCoffee] = [:] - private var menu = Menu() + private let menu: CoffeeSearching + + init(menu: CoffeeSearching) { + self.menu = menu + } func takeOrder(origin: String, table: Int) { - orders[table] = menu.lookup(origin: origin) + orders[table] = menu.search(origin: origin) } func serve() { @@ -315,7 +311,7 @@ final class CoffeeShop { /*: ### Usage */ -let coffeeShop = CoffeeShop() +let coffeeShop = CoffeeShop(menu: Menu()) coffeeShop.takeOrder(origin: "Yirgacheffe, Ethiopia", table: 1) coffeeShop.takeOrder(origin: "Buziraguhindwa, Burundi", table: 3) @@ -330,23 +326,23 @@ Protection proxy is restricting access. ### Example */ -protocol DoorOperator { +protocol DoorOpening { func open(doors: String) -> String } -class HAL9000 : DoorOperator { +final class HAL9000: DoorOpening { func open(doors: String) -> String { return ("HAL9000: Affirmative, Dave. I read you. Opened \(doors).") } } -class CurrentComputer : DoorOperator { +final class CurrentComputer: DoorOpening { private var computer: HAL9000! func authenticate(password: String) -> Bool { guard password == "pass" else { - return false; + return false } computer = HAL9000() @@ -386,13 +382,14 @@ protocol HEVSuitMedicalAid { func administerMorphine() -> String } -class HEVSuit : HEVSuitMedicalAid { +final class HEVSuit: HEVSuitMedicalAid { func administerMorphine() -> String { return "Morphine administered." } } -class HEVSuitHumanInterface : HEVSuitMedicalAid { +final class HEVSuitHumanInterface: HEVSuitMedicalAid { + lazy private var physicalSuit: HEVSuit = HEVSuit() func administerMorphine() -> String { diff --git a/Design-Patterns.playground/Pages/Structural.xcplaygroundpage/timeline.xctimeline b/Design-Patterns.playground/Pages/Structural.xcplaygroundpage/timeline.xctimeline new file mode 100644 index 0000000..bf468af --- /dev/null +++ b/Design-Patterns.playground/Pages/Structural.xcplaygroundpage/timeline.xctimeline @@ -0,0 +1,6 @@ + + + + + diff --git a/Design-Patterns.playground/contents.xcplayground b/Design-Patterns.playground/contents.xcplayground index 948fe0e..9c4add8 100644 --- a/Design-Patterns.playground/contents.xcplayground +++ b/Design-Patterns.playground/contents.xcplayground @@ -1,6 +1,7 @@ + diff --git a/Design-Patterns.playground/playground.xcworkspace/contents.xcworkspacedata b/Design-Patterns.playground/playground.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a..0000000 --- a/Design-Patterns.playground/playground.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/Design-Patterns.playground/playground.xcworkspace/xcshareddata/Design-Patterns.xccheckout b/Design-Patterns.playground/playground.xcworkspace/xcshareddata/Design-Patterns.xccheckout deleted file mode 100644 index 7ff2e0e..0000000 --- a/Design-Patterns.playground/playground.xcworkspace/xcshareddata/Design-Patterns.xccheckout +++ /dev/null @@ -1,41 +0,0 @@ - - - - - IDESourceControlProjectFavoriteDictionaryKey - - IDESourceControlProjectIdentifier - 6E6A675F-9997-43AE-BB1C-8E4B69F9AD36 - IDESourceControlProjectName - Design-Patterns - IDESourceControlProjectOriginsDictionary - - C96876E4909DB6FA99FAEC5AD77808104236AA02 - https://github.com/ochococo/Design-Patterns-In-Swift.git - - IDESourceControlProjectPath - Design-Patterns.playground - IDESourceControlProjectRelativeInstallPathDictionary - - C96876E4909DB6FA99FAEC5AD77808104236AA02 - .. - - IDESourceControlProjectURL - https://github.com/ochococo/Design-Patterns-In-Swift.git - IDESourceControlProjectVersion - 111 - IDESourceControlProjectWCCIdentifier - C96876E4909DB6FA99FAEC5AD77808104236AA02 - IDESourceControlProjectWCConfigurations - - - IDESourceControlRepositoryExtensionIdentifierKey - public.vcs.git - IDESourceControlWCCIdentifierKey - C96876E4909DB6FA99FAEC5AD77808104236AA02 - IDESourceControlWCCName - Design-Patterns-In-Swift - - - - diff --git a/GENERATE.md b/GENERATE.md index fafa908..44d6937 100644 --- a/GENERATE.md +++ b/GENERATE.md @@ -1,9 +1,8 @@ How to generate playground and zip ================================== -In Terminal type: - -every time: +Do not change the `.playground` nor `README.md` manually! +Go to `/source` and edit *.swift files instead use Terminal to go to main directory use: ```bash ./generate-playground.sh diff --git a/MyPlayground.playground/Pages/Untitled Page 2.xcplaygroundpage/Contents.swift b/MyPlayground.playground/Pages/Untitled Page 2.xcplaygroundpage/Contents.swift new file mode 100644 index 0000000..854a033 --- /dev/null +++ b/MyPlayground.playground/Pages/Untitled Page 2.xcplaygroundpage/Contents.swift @@ -0,0 +1,7 @@ +//: [Previous](@previous) + +import Foundation + +var str = "Hello, playground" + +//: [Next](@next) diff --git a/MyPlayground.playground/Pages/Untitled Page.xcplaygroundpage/Contents.swift b/MyPlayground.playground/Pages/Untitled Page.xcplaygroundpage/Contents.swift new file mode 100644 index 0000000..49c1ff6 --- /dev/null +++ b/MyPlayground.playground/Pages/Untitled Page.xcplaygroundpage/Contents.swift @@ -0,0 +1,3 @@ +import UIKit + +var str = "Hello, playground" diff --git a/MyPlayground.playground/Pages/Untitled Page.xcplaygroundpage/timeline.xctimeline b/MyPlayground.playground/Pages/Untitled Page.xcplaygroundpage/timeline.xctimeline new file mode 100644 index 0000000..bf468af --- /dev/null +++ b/MyPlayground.playground/Pages/Untitled Page.xcplaygroundpage/timeline.xctimeline @@ -0,0 +1,6 @@ + + + + + diff --git a/MyPlayground.playground/contents.xcplayground b/MyPlayground.playground/contents.xcplayground new file mode 100644 index 0000000..9f5f2f4 --- /dev/null +++ b/MyPlayground.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md index 0308481..ce7ed12 100644 --- a/PULL_REQUEST_TEMPLATE.md +++ b/PULL_REQUEST_TEMPLATE.md @@ -1,5 +1,3 @@ - - -- [ ] Do not change the `.playground` nor `README.md` manually. -- [ ] Go to `/source` and edit .swift files. -- [ ] Run: `generate-playground.sh` \ No newline at end of file +- [ ] Added description +- [ ] Linked to or created issue +- [ ] Generated files as described [GENERATE.md](https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/GENERATE.md) \ No newline at end of file diff --git a/README.md b/README.md index 5fc3d0d..c214421 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,20 @@ -Design Patterns implemented in Swift 3.0 + +Design Patterns implemented in Swift 5.0 ======================================== -A short cheat-sheet with Xcode 8.2 Playground ([Design-Patterns.playground.zip](https://raw.githubusercontent.com/ochococo/Design-Patterns-In-Swift/master/Design-Patterns.playground.zip)). + +A short cheat-sheet with Xcode 10.2 Playground ([Design-Patterns.playground.zip](https://raw.githubusercontent.com/ochococo/Design-Patterns-In-Swift/master/Design-Patterns.playground.zip)). 👷 Project maintained by: [@nsmeme](http://twitter.com/nsmeme) (Oktawian Chojnacki) 🚀 How to generate README, Playground and zip from source: [GENERATE.md](https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/GENERATE.md) -## Table of Contents - -* [Behavioral](#behavioral) -* [Creational](#creational) -* [Structural](#structural) - ```swift - - Behavioral | - [Creational](Creational) | - [Structural](Structural) +print("Welcome!") ``` + Behavioral ========== @@ -28,11 +22,8 @@ Behavioral > >**Source:** [wikipedia.org](http://en.wikipedia.org/wiki/Behavioral_pattern) -```swift -import Swift -import Foundation -``` + 🐝 Chain Of Responsibility -------------------------- @@ -43,19 +34,23 @@ The chain of responsibility pattern is used to process varied requests, each of ```swift -final class MoneyPile { +protocol Withdrawing { + func withdraw(amount: Int) -> Bool +} + +final class MoneyPile: Withdrawing { let value: Int var quantity: Int - var nextPile: MoneyPile? + var next: Withdrawing? - init(value: Int, quantity: Int, nextPile: MoneyPile?) { + init(value: Int, quantity: Int, next: Withdrawing?) { self.value = value self.quantity = quantity - self.nextPile = nextPile + self.next = next } - func canWithdraw(amount: Int) -> Bool { + func withdraw(amount: Int) -> Bool { var amount = amount @@ -79,28 +74,29 @@ final class MoneyPile { return true } - if let next = self.nextPile { - return next.canWithdraw(amount: amount) + if let next = self.next { + return next.withdraw(amount: amount) } return false } } -final class ATM { - private var hundred: MoneyPile - private var fifty: MoneyPile - private var twenty: MoneyPile - private var ten: MoneyPile +final class ATM: Withdrawing { - private var startPile: MoneyPile { + private var hundred: Withdrawing + private var fifty: Withdrawing + private var twenty: Withdrawing + private var ten: Withdrawing + + private var startPile: Withdrawing { return self.hundred } - init(hundred: MoneyPile, - fifty: MoneyPile, - twenty: MoneyPile, - ten: MoneyPile) { + init(hundred: Withdrawing, + fifty: Withdrawing, + twenty: Withdrawing, + ten: Withdrawing) { self.hundred = hundred self.fifty = fifty @@ -108,8 +104,8 @@ final class ATM { self.ten = ten } - func canWithdraw(amount: Int) -> String { - return "Can withdraw: \(self.startPile.canWithdraw(amount: amount))" + func withdraw(amount: Int) -> Bool { + return startPile.withdraw(amount: amount) } } ``` @@ -117,25 +113,16 @@ final class ATM { ### Usage ```swift - // Create piles of money and link them together 10 < 20 < 50 < 100.** -let ten = MoneyPile(value: 10, quantity: 6, nextPile: nil) -let twenty = MoneyPile(value: 20, quantity: 2, nextPile: ten) -let fifty = MoneyPile(value: 50, quantity: 2, nextPile: twenty) -let hundred = MoneyPile(value: 100, quantity: 1, nextPile: fifty) +let ten = MoneyPile(value: 10, quantity: 6, next: nil) +let twenty = MoneyPile(value: 20, quantity: 2, next: ten) +let fifty = MoneyPile(value: 50, quantity: 2, next: twenty) +let hundred = MoneyPile(value: 100, quantity: 1, next: fifty) // Build ATM. var atm = ATM(hundred: hundred, fifty: fifty, twenty: twenty, ten: ten) -atm.canWithdraw(amount: 310) // Cannot because ATM has only 300 -atm.canWithdraw(amount: 100) // Can withdraw - 1x100 -atm.canWithdraw(amount: 165) // Cannot withdraw because ATM doesn't has bill with value of 5 -atm.canWithdraw(amount: 30) // Can withdraw - 1x20, 2x10 -``` - ->**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Chain-Of-Responsibility) - -```swift - +atm.withdraw(amount: 310) // Cannot because ATM has only 300 +atm.withdraw(amount: 100) // Can withdraw - 1x100 ``` 👫 Command @@ -146,12 +133,11 @@ The command pattern is used to express a request, including the call to be made ### Example: ```swift - protocol DoorCommand { func execute() -> String } -class OpenCommand : DoorCommand { +final class OpenCommand: DoorCommand { let doors:String required init(doors: String) { @@ -163,7 +149,7 @@ class OpenCommand : DoorCommand { } } -class CloseCommand : DoorCommand { +final class CloseCommand: DoorCommand { let doors:String required init(doors: String) { @@ -175,7 +161,7 @@ class CloseCommand : DoorCommand { } } -class HAL9000DoorsOperations { +final class HAL9000DoorsOperations { let openCommand: DoorCommand let closeCommand: DoorCommand @@ -197,7 +183,6 @@ class HAL9000DoorsOperations { ### Usage: ```swift - let podBayDoors = "Pod Bay Doors" let doorModule = HAL9000DoorsOperations(doors:podBayDoors) @@ -214,7 +199,6 @@ The interpreter pattern is used to evaluate sentences in a language. ```swift - protocol IntegerExpression { func evaluate(_ context: IntegerContext) -> Int func replace(character: Character, integerExpression: IntegerExpression) -> IntegerExpression @@ -284,7 +268,6 @@ final class AddExpression: IntegerExpression { ### Usage ```swift - var context = IntegerContext() var a = IntegerVariableExpression(name: "A") @@ -300,12 +283,6 @@ context.assign(expression: c, value: 3) var result = expression.evaluate(context) ``` ->**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Interpreter) - -```swift - -``` - 🍫 Iterator ----------- @@ -314,7 +291,6 @@ The iterator pattern is used to provide a standard interface for traversing a co ### Example: ```swift - struct Novella { let name: String } @@ -348,7 +324,6 @@ extension Novellas: Sequence { ### Usage ```swift - let greatNovellas = Novellas(novellas: [Novella(name: "The Mist")] ) for novella in greatNovellas { @@ -364,7 +339,6 @@ The mediator pattern is used to reduce coupling between classes that communicate ### Example ```swift - protocol Receiver { associatedtype MessageType func receive(message: MessageType) @@ -410,7 +384,6 @@ final class MessageMediator: Sender { ### Usage ```swift - func spamMonster(message: String, worker: MessageMediator) { worker.send(message: message) } @@ -423,11 +396,6 @@ messagesMediator.add(recipient: user0) messagesMediator.add(recipient: user1) spamMonster(message: "I'd Like to Add you to My Professional Network", worker: messagesMediator) -``` - ->**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Mediator) - -```swift ``` @@ -439,14 +407,12 @@ The memento pattern is used to capture the current state of an object and store ### Example ```swift - -typealias Memento = NSDictionary +typealias Memento = [String: String] ``` Originator ```swift - protocol MementoConvertible { var memento: Memento { get } init?(memento: Memento) @@ -468,8 +434,8 @@ struct GameState: MementoConvertible { } init?(memento: Memento) { - guard let mementoChapter = memento[Keys.chapter] as? String, - let mementoWeapon = memento[Keys.weapon] as? String else { + guard let mementoChapter = memento[Keys.chapter], + let mementoWeapon = memento[Keys.weapon] else { return nil } @@ -486,26 +452,24 @@ struct GameState: MementoConvertible { Caretaker ```swift - enum CheckPoint { + + private static let defaults = UserDefaults.standard + static func save(_ state: MementoConvertible, saveName: String) { - let defaults = UserDefaults.standard defaults.set(state.memento, forKey: saveName) defaults.synchronize() } - static func restore(saveName: String) -> Memento? { - let defaults = UserDefaults.standard - - return defaults.object(forKey: saveName) as? Memento + static func restore(saveName: String) -> Any? { + return defaults.object(forKey: saveName) } } ``` - ### Usage +### Usage ```swift - var gameState = GameState(chapter: "Black Mesa Inbound", weapon: "Crowbar") gameState.chapter = "Anomalous Materials" @@ -520,7 +484,7 @@ gameState.chapter = "Office Complex" gameState.weapon = "Crossbow" CheckPoint.save(gameState, saveName: "gameState3") -if let memento = CheckPoint.restore(saveName: "gameState1") { +if let memento = CheckPoint.restore(saveName: "gameState1") as? Memento { let finalState = GameState(memento: memento) dump(finalState) } @@ -535,7 +499,6 @@ Other objects subscribe to be immediately notified of any changes. ### Example ```swift - protocol PropertyObserver : class { func willChange(propertyName: String, newPropertyValue: Any?) func didChange(propertyName: String, oldPropertyValue: Any?) @@ -575,19 +538,12 @@ final class Observer : PropertyObserver { ### Usage ```swift - var observerInstance = Observer() var testChambers = TestChambers() testChambers.observer = observerInstance testChambers.testChamberNumber += 1 ``` ->**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Observer) - -```swift - -``` - 🐉 State --------- @@ -597,7 +553,6 @@ The pattern allows the class for an object to apparently change at run-time. ### Example ```swift - final class Context { private var state: State = UnauthorizedState() @@ -616,7 +571,6 @@ final class Context { func changeStateToUnauthorized() { state = UnauthorizedState() } - } protocol State { @@ -644,7 +598,6 @@ class AuthorizedState: State { ### Usage ```swift - let userContext = Context() (userContext.isAuthorized, userContext.userId) userContext.changeStateToAuthorized(userId: "admin") @@ -653,12 +606,6 @@ userContext.changeStateToUnauthorized() (userContext.isAuthorized, userContext.userId) ``` ->**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-State) - -```swift - -``` - 💡 Strategy ----------- @@ -668,134 +615,57 @@ The strategy pattern is used to create an interchangeable family of algorithms f ```swift -protocol PrintStrategy { - func print(_ string: String) -> String -} - -final class Printer { - - private let strategy: PrintStrategy - - func print(_ string: String) -> String { - return self.strategy.print(string) - } - - init(strategy: PrintStrategy) { - self.strategy = strategy - } +struct TestSubject { + let pupilDiameter: Double + let blushResponse: Double + let isOrganic: Bool } -final class UpperCaseStrategy: PrintStrategy { - func print(_ string: String) -> String { - return string.uppercased() - } +protocol RealnessTesting: AnyObject { + func testRealness(_ testSubject: TestSubject) -> Bool } -final class LowerCaseStrategy: PrintStrategy { - func print(_ string:String) -> String { - return string.lowercased() +final class VoightKampffTest: RealnessTesting { + func testRealness(_ testSubject: TestSubject) -> Bool { + return testSubject.pupilDiameter < 30.0 || testSubject.blushResponse == 0.0 } } -``` - -### Usage - -```swift - -var lower = Printer(strategy: LowerCaseStrategy()) -lower.print("O tempora, o mores!") - -var upper = Printer(strategy: UpperCaseStrategy()) -upper.print("O tempora, o mores!") -``` - ->**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Strategy) - -```swift - -``` - -🍪 Template ------------ - -The Template Pattern is used when two or more implementations of an -algorithm exist. The template is defined and then built upon with further -variations. Use this method when most (or all) subclasses need to implement -the same behavior. Traditionally, this would be accomplished with abstract -classes and protected methods (as in Java). However in Swift, because -abstract classes don't exist (yet - maybe someday), we need to accomplish -the behavior using interface delegation. - - -### Example - -```swift - - -protocol ICodeGenerator { - func crossCompile() -} -protocol IGeneratorPhases { - func collectSource() - func crossCompile() -} - -class CodeGenerator : ICodeGenerator{ - var delegate: IGeneratorPhases - - init(delegate: IGeneratorPhases) { - self.delegate = delegate +final class GeneticTest: RealnessTesting { + func testRealness(_ testSubject: TestSubject) -> Bool { + return testSubject.isOrganic } - - private func fetchDataforGeneration(){ - //common implementation - print("fetchDataforGeneration invoked") - } - - //Template method - final func crossCompile() { - fetchDataforGeneration() - delegate.collectSource() - delegate.crossCompile() - } - } -class HTMLGeneratorPhases : IGeneratorPhases { - func collectSource() { - print("HTMLGeneratorPhases collectSource() executed") - } +final class BladeRunner { + private let strategy: RealnessTesting - func crossCompile() { - print("HTMLGeneratorPhases crossCompile() executed") + init(test: RealnessTesting) { + self.strategy = test } -} -class JSONGeneratorPhases : IGeneratorPhases { - func collectSource() { - print("JSONGeneratorPhases collectSource() executed") - } - - func crossCompile() { - print("JSONGeneratorPhases crossCompile() executed") + func testIfAndroid(_ testSubject: TestSubject) -> Bool { + return !strategy.testRealness(testSubject) } } - - ``` -### Usage - + ### Usage + ```swift +let rachel = TestSubject(pupilDiameter: 30.2, + blushResponse: 0.3, + isOrganic: false) -let htmlGen : ICodeGenerator = CodeGenerator(delegate: HTMLGeneratorPhases()) -let jsonGen: ICodeGenerator = CodeGenerator(delegate: JSONGeneratorPhases()) +// Deckard is using a traditional test +let deckard = BladeRunner(test: VoightKampffTest()) +let isRachelAndroid = deckard.testIfAndroid(rachel) -htmlGen.crossCompile() -jsonGen.crossCompile() +// Gaff is using a very precise method +let gaff = BladeRunner(test: GeneticTest()) +let isDeckardAndroid = gaff.testIfAndroid(rachel) ``` 🏃 Visitor @@ -806,43 +676,40 @@ The visitor pattern is used to separate a relatively complex set of structured d ### Example ```swift - protocol PlanetVisitor { func visit(planet: PlanetAlderaan) func visit(planet: PlanetCoruscant) func visit(planet: PlanetTatooine) - func visit(planet: MoonJedah) + func visit(planet: MoonJedha) } protocol Planet { func accept(visitor: PlanetVisitor) } -class MoonJedah: Planet { +final class MoonJedha: Planet { func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) } } -class PlanetAlderaan: Planet { +final class PlanetAlderaan: Planet { func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) } } -class PlanetCoruscant: Planet { +final class PlanetCoruscant: Planet { func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) } } -class PlanetTatooine: Planet { +final class PlanetTatooine: Planet { func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) } } - - -class NameVisitor: PlanetVisitor { +final class NameVisitor: PlanetVisitor { var name = "" func visit(planet: PlanetAlderaan) { name = "Alderaan" } func visit(planet: PlanetCoruscant) { name = "Coruscant" } func visit(planet: PlanetTatooine) { name = "Tatooine" } - func visit(planet: MoonJedah) { name = "Jedah" } + func visit(planet: MoonJedha) { name = "Jedha" } } ``` @@ -850,26 +717,18 @@ class NameVisitor: PlanetVisitor { ### Usage ```swift - -let planets: [Planet] = [PlanetAlderaan(), PlanetCoruscant(), PlanetTatooine(), MoonJedah()] +let planets: [Planet] = [PlanetAlderaan(), PlanetCoruscant(), PlanetTatooine(), MoonJedha()] let names = planets.map { (planet: Planet) -> String in let visitor = NameVisitor() planet.accept(visitor: visitor) - return visitor.name + + return visitor.name } names ``` ->**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Visitor) - -```swift - - [Behavioral](Behavioral) | - Creational | - [Structural](Structural) -``` Creational ========== @@ -878,11 +737,8 @@ Creational > >**Source:** [wikipedia.org](http://en.wikipedia.org/wiki/Creational_pattern) -```swift -import Swift -import Foundation -``` + 🌰 Abstract Factory ------------------- @@ -892,62 +748,53 @@ The "family" of objects created by the factory are determined at run-time. ### Example -```swift - -``` - Protocols ```swift -protocol Decimal { - func stringValue() -> String - // factory - static func make(string : String) -> Decimal +protocol BurgerDescribing { + var ingredients: [String] { get } } -typealias NumberFactory = (String) -> Decimal +struct CheeseBurger: BurgerDescribing { + let ingredients: [String] +} -// Number implementations with factory methods +protocol BurgerMaking { + func make() -> BurgerDescribing +} -struct NextStepNumber: Decimal { - private var nextStepNumber: NSNumber +// Number implementations with factory methods - func stringValue() -> String { return nextStepNumber.stringValue } - - // factory - static func make(string: String) -> Decimal { - return NextStepNumber(nextStepNumber: NSNumber(value: (string as NSString).longLongValue)) +final class BigKahunaBurger: BurgerMaking { + func make() -> BurgerDescribing { + return CheeseBurger(ingredients: ["Cheese", "Burger", "Lettuce", "Tomato"]) } } -struct SwiftNumber : Decimal { - private var swiftInt: Int - - func stringValue() -> String { return "\(swiftInt)" } - - // factory - static func make(string: String) -> Decimal { - return SwiftNumber(swiftInt:(string as NSString).integerValue) +final class JackInTheBox: BurgerMaking { + func make() -> BurgerDescribing { + return CheeseBurger(ingredients: ["Cheese", "Burger", "Tomato", "Onions"]) } } + ``` Abstract factory ```swift -enum NumberType { - case nextStep, swift -} +enum BurgerFactoryType: BurgerMaking { + + case bigKahuna + case jackInTheBox -enum NumberHelper { - static func factory(for type: NumberType) -> NumberFactory { - switch type { - case .nextStep: - return NextStepNumber.make - case .swift: - return SwiftNumber.make + func make() -> BurgerDescribing { + switch self { + case .bigKahuna: + return BigKahunaBurger().make() + case .jackInTheBox: + return JackInTheBox().make() } } } @@ -956,14 +803,8 @@ enum NumberHelper { ### Usage ```swift - -let factoryOne = NumberHelper.factory(for: .nextStep) -let numberOne = factoryOne("1") -numberOne.stringValue() - -let factoryTwo = NumberHelper.factory(for: .swift) -let numberTwo = factoryTwo("2") -numberTwo.stringValue() +let bigKahuna = BurgerFactoryType.bigKahuna.make() +let jackInTheBox = BurgerFactoryType.jackInTheBox.make() ``` 👷 Builder @@ -975,8 +816,7 @@ An external class controls the construction algorithm. ### Example ```swift - -class DeathStarBuilder { +final class DeathStarBuilder { var x: Double? var y: Double? @@ -1015,7 +855,6 @@ struct DeathStar : CustomStringConvertible { ### Usage ```swift - let empire = DeathStarBuilder { builder in builder.x = 0.1 builder.y = 0.2 @@ -1025,12 +864,6 @@ let empire = DeathStarBuilder { builder in let deathStar = DeathStar(builder:empire) ``` ->**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Builder) - -```swift - -``` - 🏭 Factory Method ----------------- @@ -1039,43 +872,45 @@ The factory pattern is used to replace class constructors, abstracting the proce ### Example ```swift - -protocol Currency { - func symbol() -> String - func code() -> String +protocol CurrencyDescribing { + var symbol: String { get } + var code: String { get } } -class Euro : Currency { - func symbol() -> String { +final class Euro: CurrencyDescribing { + var symbol: String { return "€" } - func code() -> String { + var code: String { return "EUR" } } -class UnitedStatesDolar : Currency { - func symbol() -> String { +final class UnitedStatesDolar: CurrencyDescribing { + var symbol: String { return "$" } - func code() -> String { + var code: String { return "USD" } } enum Country { - case unitedStates, spain, uk, greece + case unitedStates + case spain + case uk + case greece } enum CurrencyFactory { - static func currency(for country:Country) -> Currency? { + static func currency(for country: Country) -> CurrencyDescribing? { switch country { - case .spain, .greece : + case .spain, .greece: return Euro() - case .unitedStates : + case .unitedStates: return UnitedStatesDolar() default: return nil @@ -1088,13 +923,12 @@ enum CurrencyFactory { ### Usage ```swift - let noCurrencyCode = "No Currency Code Available" -CurrencyFactory.currency(for: .greece)?.code() ?? noCurrencyCode -CurrencyFactory.currency(for: .spain)?.code() ?? noCurrencyCode -CurrencyFactory.currency(for: .unitedStates)?.code() ?? noCurrencyCode -CurrencyFactory.currency(for: .uk)?.code() ?? noCurrencyCode +CurrencyFactory.currency(for: .greece)?.code ?? noCurrencyCode +CurrencyFactory.currency(for: .spain)?.code ?? noCurrencyCode +CurrencyFactory.currency(for: .unitedStates)?.code ?? noCurrencyCode +CurrencyFactory.currency(for: .uk)?.code ?? noCurrencyCode ``` 🃏 Prototype @@ -1106,17 +940,17 @@ This practise is particularly useful when the construction of a new object is in ### Example ```swift +struct MoonWorker { -class ChungasRevengeDisplay { - var name: String? - let font: String + let name: String + var health: Int = 100 - init(font: String) { - self.font = font + init(name: String) { + self.name = name } - func clone() -> ChungasRevengeDisplay { - return ChungasRevengeDisplay(font:self.font) + func clone() -> MoonWorker { + return MoonWorker(name: name) } } ``` @@ -1124,23 +958,16 @@ class ChungasRevengeDisplay { ### Usage ```swift +let prototype = MoonWorker(name: "Sam Bell") -let Prototype = ChungasRevengeDisplay(font:"GotanProject") +var bell1 = prototype.clone() +bell1.health = 12 -let Philippe = Prototype.clone() -Philippe.name = "Philippe" - -let Christoph = Prototype.clone() -Christoph.name = "Christoph" - -let Eduardo = Prototype.clone() -Eduardo.name = "Eduardo" -``` - ->**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Prototype) - -```swift +var bell2 = prototype.clone() +bell2.health = 23 +var bell3 = prototype.clone() +bell3.health = 0 ``` 💍 Singleton @@ -1153,9 +980,9 @@ There are very few applications, do not overuse this pattern! ### Example: ```swift +final class ElonMusk { -class DeathStarSuperlaser { - static let sharedInstance = DeathStarSuperlaser() + static let shared = ElonMusk() private init() { // Private initialization to ensure just one instance is created. @@ -1166,13 +993,10 @@ class DeathStarSuperlaser { ### Usage: ```swift - -let laser = DeathStarSuperlaser.sharedInstance - [Behavioral](Behavioral) | - [Creational](Creational) | - Structural +let elon = ElonMusk.shared // There is only one Elon Musk folks. ``` + Structural ========== @@ -1180,11 +1004,8 @@ Structural > >**Source:** [wikipedia.org](http://en.wikipedia.org/wiki/Structural_pattern) -```swift -import Swift -import Foundation -``` + 🔌 Adapter ---------- @@ -1194,22 +1015,20 @@ The adapter pattern is used to provide a link between two otherwise incompatible ### Example ```swift - -protocol OlderDeathStarSuperLaserAiming { - var angleV: NSNumber {get} - var angleH: NSNumber {get} +protocol NewDeathStarSuperLaserAiming { + var angleV: Double { get } + var angleH: Double { get } } ``` **Adaptee** ```swift +struct OldDeathStarSuperlaserTarget { + let angleHorizontal: Float + let angleVertical: Float -struct DeathStarSuperlaserTarget { - let angleHorizontal: Double - let angleVertical: Double - - init(angleHorizontal:Double, angleVertical:Double) { + init(angleHorizontal: Float, angleVertical: Float) { self.angleHorizontal = angleHorizontal self.angleVertical = angleVertical } @@ -1219,19 +1038,19 @@ struct DeathStarSuperlaserTarget { **Adapter** ```swift +struct NewDeathStarSuperlaserTarget: NewDeathStarSuperLaserAiming { -struct OldDeathStarSuperlaserTarget : OlderDeathStarSuperLaserAiming { - private let target : DeathStarSuperlaserTarget + private let target: OldDeathStarSuperlaserTarget - var angleV:NSNumber { - return NSNumber(value: target.angleVertical) + var angleV: Double { + return Double(target.angleVertical) } - var angleH:NSNumber { - return NSNumber(value: target.angleHorizontal) + var angleH: Double { + return Double(target.angleHorizontal) } - init(_ target:DeathStarSuperlaserTarget) { + init(_ target: OldDeathStarSuperlaserTarget) { self.target = target } } @@ -1240,18 +1059,11 @@ struct OldDeathStarSuperlaserTarget : OlderDeathStarSuperLaserAiming { ### Usage ```swift +let target = OldDeathStarSuperlaserTarget(angleHorizontal: 14.0, angleVertical: 12.0) +let newFormat = NewDeathStarSuperlaserTarget(target) -let target = DeathStarSuperlaserTarget(angleHorizontal: 14.0, angleVertical: 12.0) -let oldFormat = OldDeathStarSuperlaserTarget(target) - -oldFormat.angleH -oldFormat.angleV -``` - ->**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Adapter) - -```swift - +newFormat.angleH +newFormat.angleV ``` 🌉 Bridge @@ -1262,9 +1074,8 @@ The bridge pattern is used to separate the abstract elements of a class from the ### Example ```swift - protocol Switch { - var appliance: Appliance {get set} + var appliance: Appliance { get set } func turnOn() } @@ -1272,7 +1083,7 @@ protocol Appliance { func run() } -class RemoteControl: Switch { +final class RemoteControl: Switch { var appliance: Appliance func turnOn() { @@ -1284,13 +1095,13 @@ class RemoteControl: Switch { } } -class TV: Appliance { +final class TV: Appliance { func run() { print("tv turned on"); } } -class VacuumCleaner: Appliance { +final class VacuumCleaner: Appliance { func run() { print("vacuum cleaner turned on") } @@ -1300,11 +1111,10 @@ class VacuumCleaner: Appliance { ### Usage ```swift - -var tvRemoteControl = RemoteControl(appliance: TV()) +let tvRemoteControl = RemoteControl(appliance: TV()) tvRemoteControl.turnOn() -var fancyVacuumCleanerRemoteControl = RemoteControl(appliance: VacuumCleaner()) +let fancyVacuumCleanerRemoteControl = RemoteControl(appliance: VacuumCleaner()) fancyVacuumCleanerRemoteControl.turnOn() ``` @@ -1315,14 +1125,9 @@ The composite pattern is used to create hierarchical, recursive tree structures ### Example -```swift - -``` - Component ```swift - protocol Shape { func draw(fillColor: String) } @@ -1331,14 +1136,13 @@ protocol Shape { Leafs ```swift - -final class Square : Shape { +final class Square: Shape { func draw(fillColor: String) { print("Drawing a Square with color \(fillColor)") } } -final class Circle : Shape { +final class Circle: Shape { func draw(fillColor: String) { print("Drawing a circle with color \(fillColor)") } @@ -1349,11 +1153,11 @@ final class Circle : Shape { Composite ```swift +final class Whiteboard: Shape { -final class Whiteboard : Shape { - lazy var shapes = [Shape]() + private lazy var shapes = [Shape]() - init(_ shapes:Shape...) { + init(_ shapes: Shape...) { self.shapes = shapes } @@ -1368,7 +1172,6 @@ final class Whiteboard : Shape { ### Usage: ```swift - var whiteboard = Whiteboard(Circle(), Square()) whiteboard.draw(fillColor: "Red") ``` @@ -1382,64 +1185,48 @@ This provides a flexible alternative to using inheritance to modify behaviour. ### Example ```swift - -protocol Coffee { - func getCost() -> Double - func getIngredients() -> String +protocol CostHaving { + var cost: Double { get } } -class SimpleCoffee: Coffee { - func getCost() -> Double { - return 1.0 - } - - func getIngredients() -> String { - return "Coffee" - } +protocol IngredientsHaving { + var ingredients: [String] { get } } -class CoffeeDecorator: Coffee { - private let decoratedCoffee: Coffee - fileprivate let ingredientSeparator: String = ", " - - required init(decoratedCoffee: Coffee) { - self.decoratedCoffee = decoratedCoffee - } +typealias BeverageDataHaving = CostHaving & IngredientsHaving - func getCost() -> Double { - return decoratedCoffee.getCost() - } +struct SimpleCoffee: BeverageDataHaving { + let cost: Double = 1.0 + let ingredients = ["Water", "Coffee"] +} - func getIngredients() -> String { - return decoratedCoffee.getIngredients() - } +protocol BeverageHaving: BeverageDataHaving { + var beverage: BeverageDataHaving { get } } -final class Milk: CoffeeDecorator { - required init(decoratedCoffee: Coffee) { - super.init(decoratedCoffee: decoratedCoffee) - } +struct Milk: BeverageHaving { + + let beverage: BeverageDataHaving - override func getCost() -> Double { - return super.getCost() + 0.5 + var cost: Double { + return beverage.cost + 0.5 } - override func getIngredients() -> String { - return super.getIngredients() + ingredientSeparator + "Milk" + var ingredients: [String] { + return beverage.ingredients + ["Milk"] } } -final class WhipCoffee: CoffeeDecorator { - required init(decoratedCoffee: Coffee) { - super.init(decoratedCoffee: decoratedCoffee) - } +struct WhipCoffee: BeverageHaving { - override func getCost() -> Double { - return super.getCost() + 0.7 + let beverage: BeverageDataHaving + + var cost: Double { + return beverage.cost + 0.5 } - override func getIngredients() -> String { - return super.getIngredients() + ingredientSeparator + "Whip" + var ingredients: [String] { + return beverage.ingredients + ["Whip"] } } ``` @@ -1447,13 +1234,12 @@ final class WhipCoffee: CoffeeDecorator { ### Usage: ```swift - -var someCoffee: Coffee = SimpleCoffee() -print("Cost : \(someCoffee.getCost()); Ingredients: \(someCoffee.getIngredients())") -someCoffee = Milk(decoratedCoffee: someCoffee) -print("Cost : \(someCoffee.getCost()); Ingredients: \(someCoffee.getIngredients())") -someCoffee = WhipCoffee(decoratedCoffee: someCoffee) -print("Cost : \(someCoffee.getCost()); Ingredients: \(someCoffee.getIngredients())") +var someCoffee: BeverageDataHaving = SimpleCoffee() +print("Cost: \(someCoffee.cost); Ingredients: \(someCoffee.ingredients)") +someCoffee = Milk(beverage: someCoffee) +print("Cost: \(someCoffee.cost); Ingredients: \(someCoffee.ingredients)") +someCoffee = WhipCoffee(beverage: someCoffee) +print("Cost: \(someCoffee.cost); Ingredients: \(someCoffee.ingredients)") ``` 🎁 Façade @@ -1464,29 +1250,36 @@ The facade pattern is used to define a simplified interface to a more complex su ### Example ```swift +final class Defaults { -enum Eternal { + private let defaults: UserDefaults - static func set(_ object: Any, forKey defaultName: String) { - let defaults: UserDefaults = UserDefaults.standard - defaults.set(object, forKey:defaultName) - defaults.synchronize() + init(defaults: UserDefaults = .standard) { + self.defaults = defaults } - static func object(forKey key: String) -> AnyObject! { - let defaults: UserDefaults = UserDefaults.standard - return defaults.object(forKey: key) as AnyObject! - } + subscript(key: String) -> String? { + get { + return defaults.string(forKey: key) + } + set { + defaults.set(newValue, forKey: key) + } + } } ``` ### Usage ```swift +let storage = Defaults() + +// Store +storage["Bishop"] = "Disconnect me. I’d rather be nothing" -Eternal.set("Disconnect me. I’d rather be nothing", forKey:"Bishop") -Eternal.object(forKey: "Bishop") +// Read +storage["Bishop"] ``` ## 🍃 Flyweight @@ -1494,26 +1287,21 @@ The flyweight pattern is used to minimize memory usage or computational expenses ### Example ```swift +// Instances of SpecialityCoffee will be the Flyweights +struct SpecialityCoffee { + let origin: String +} -// Instances of CoffeeFlavour will be the Flyweights -final class SpecialityCoffee: CustomStringConvertible { - var origin: String - var description: String { - get { - return origin - } - } - - init(origin: String) { - self.origin = origin - } +protocol CoffeeSearching { + func search(origin: String) -> SpecialityCoffee? } -// Menu acts as a factory and cache for CoffeeFlavour flyweight objects -final class Menu { +// Menu acts as a factory and cache for SpecialityCoffee flyweight objects +final class Menu: CoffeeSearching { + private var coffeeAvailable: [String: SpecialityCoffee] = [:] - func lookup(origin: String) -> SpecialityCoffee? { + func search(origin: String) -> SpecialityCoffee? { if coffeeAvailable.index(forKey: origin) == nil { coffeeAvailable[origin] = SpecialityCoffee(origin: origin) } @@ -1524,10 +1312,14 @@ final class Menu { final class CoffeeShop { private var orders: [Int: SpecialityCoffee] = [:] - private var menu = Menu() + private let menu: CoffeeSearching + + init(menu: CoffeeSearching) { + self.menu = menu + } func takeOrder(origin: String, table: Int) { - orders[table] = menu.lookup(origin: origin) + orders[table] = menu.search(origin: origin) } func serve() { @@ -1541,8 +1333,7 @@ final class CoffeeShop { ### Usage ```swift - -let coffeeShop = CoffeeShop() +let coffeeShop = CoffeeShop(menu: Menu()) coffeeShop.takeOrder(origin: "Yirgacheffe, Ethiopia", table: 1) coffeeShop.takeOrder(origin: "Buziraguhindwa, Burundi", table: 3) @@ -1559,24 +1350,23 @@ Protection proxy is restricting access. ### Example ```swift - -protocol DoorOperator { +protocol DoorOpening { func open(doors: String) -> String } -class HAL9000 : DoorOperator { +final class HAL9000: DoorOpening { func open(doors: String) -> String { return ("HAL9000: Affirmative, Dave. I read you. Opened \(doors).") } } -class CurrentComputer : DoorOperator { +final class CurrentComputer: DoorOpening { private var computer: HAL9000! func authenticate(password: String) -> Bool { guard password == "pass" else { - return false; + return false } computer = HAL9000() @@ -1598,7 +1388,6 @@ class CurrentComputer : DoorOperator { ### Usage ```swift - let computer = CurrentComputer() let podBay = "Pod Bay Doors" @@ -1617,18 +1406,18 @@ Virtual proxy is used for loading object on demand. ### Example ```swift - protocol HEVSuitMedicalAid { func administerMorphine() -> String } -class HEVSuit : HEVSuitMedicalAid { +final class HEVSuit: HEVSuitMedicalAid { func administerMorphine() -> String { return "Morphine administered." } } -class HEVSuitHumanInterface : HEVSuitMedicalAid { +final class HEVSuitHumanInterface: HEVSuitMedicalAid { + lazy private var physicalSuit: HEVSuit = HEVSuit() func administerMorphine() -> String { @@ -1640,7 +1429,6 @@ class HEVSuitHumanInterface : HEVSuitMedicalAid { ### Usage ```swift - let humanInterface = HEVSuitHumanInterface() humanInterface.administerMorphine() ``` @@ -1650,6 +1438,3 @@ Info ==== 📖 Descriptions from: [Gang of Four Design Patterns Reference Sheet](http://www.blackwasp.co.uk/GangOfFour.aspx) - - -```swift diff --git a/generate-playground.sh b/generate-playground.sh index 262df87..12878a3 100755 --- a/generate-playground.sh +++ b/generate-playground.sh @@ -1,34 +1,63 @@ #!/bin/bash -cleanThisMessForReadme () { +# Note: I think this part is absolute garbage but it's a snapshot of my current skills with Bash. +# Would love to rewrite it in Swift soon. + +combineSwift() { + cat source/startComment > $2 + cat $1/header.md >> $2 + cat source/contents.md >> $2 + cat source/endComment >> $2 + cat source/imports.swift >> $2 + cat $1/*.swift >> $2 + { rm $2 && awk '{gsub("\\*//\\*:", "", $0); print}' > $2; } < $2 +} - FILENAME=$1 +move() { + mv $1.swift Design-Patterns.playground/Pages/$1.xcplaygroundpage/Contents.swift +} - { rm $FILENAME && awk '{gsub("\\*/", "\n```swift\n", $0); print}' > $FILENAME; } < $FILENAME - { rm $FILENAME && awk '{gsub("\\*//\\*:", "", $0); print}' > $FILENAME; } < $FILENAME - { rm $FILENAME && awk '{gsub("/\\*:", "```\n", $0); print}' > $FILENAME; } < $FILENAME - { rm $FILENAME && awk '{gsub("//\\*:", "", $0); print}' > $FILENAME; } < $FILENAME - { rm $FILENAME && awk '{gsub("//:", "", $0); print}' > $FILENAME; } < $FILENAME - { rm $FILENAME && awk 'NR>1{print buf}{buf = $0}' > $FILENAME; } < $FILENAME +playground() { + combineSwift source/$1 $1.swift + move $1 } -cat source/behavioral/* > ./Behavioral.swift -cat source/creational/* > ./Creational.swift -cat source/structural/* > ./Structural.swift +combineMarkdown() { + cat $1/header.md > $2 + + { rm $2 && awk '{gsub("\\*/", "", $0); print}' > $2; } < $2 + { rm $2 && awk '{gsub("/\\*:", "", $0); print}' > $2; } < $2 + + cat source/startSwiftCode >> $2 + cat $1/*.swift >> $2 -cp ./Behavioral.swift ./Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift -cp ./Creational.swift ./Design-Patterns.playground/Pages/Creational.xcplaygroundpage/Contents.swift -cp ./Structural.swift ./Design-Patterns.playground/Pages/Structural.xcplaygroundpage/Contents.swift + { rm $2 && awk '{gsub("\\*//\\*:", "", $0); print}' > $2; } < $2 + { rm $2 && awk '{gsub("\\*/", "\n```swift", $0); print}' > $2; } < $2 + { rm $2 && awk '{gsub("/\\*:", "```\n", $0); print}' > $2; } < $2 + + cat source/endSwiftCode >> $2 -cat source/header.swift source/*/* source/footer.swift > ./contents.swift + { rm $2 && awk '{gsub("```swift```", "", $0); print}' > $2; } < $2 -cleanThisMessForReadme ./contents.swift + cat $2 >> README.md + rm $2 +} + +readme() { + combineMarkdown source/$1 $1.md +} -cp ./contents.swift ./README.md +playground Index +playground Behavioral +playground Creational +playground Structural zip -r -X Design-Patterns.playground.zip ./Design-Patterns.playground -rm ./Behavioral.swift -rm ./Creational.swift -rm ./Structural.swift -rm ./contents.swift +echo "" > README.md + +readme Index +readme Behavioral +readme Creational +readme Structural +cat source/footer.md >> README.md \ No newline at end of file diff --git a/source/Index/header.md b/source/Index/header.md new file mode 100644 index 0000000..9b34f8f --- /dev/null +++ b/source/Index/header.md @@ -0,0 +1,9 @@ + +Design Patterns implemented in Swift 5.0 +======================================== + +A short cheat-sheet with Xcode 10.2 Playground ([Design-Patterns.playground.zip](https://raw.githubusercontent.com/ochococo/Design-Patterns-In-Swift/master/Design-Patterns.playground.zip)). + +👷 Project maintained by: [@nsmeme](http://twitter.com/nsmeme) (Oktawian Chojnacki) + +🚀 How to generate README, Playground and zip from source: [GENERATE.md](https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/GENERATE.md) diff --git a/source/Index/welcome.swift b/source/Index/welcome.swift new file mode 100644 index 0000000..a707971 --- /dev/null +++ b/source/Index/welcome.swift @@ -0,0 +1,2 @@ + +print("Welcome!") diff --git a/source/behavioral/chain_of_responsibility.swift b/source/behavioral/chain_of_responsibility.swift index 7ea5764..cfe527c 100644 --- a/source/behavioral/chain_of_responsibility.swift +++ b/source/behavioral/chain_of_responsibility.swift @@ -6,19 +6,24 @@ The chain of responsibility pattern is used to process varied requests, each of ### Example: */ -final class MoneyPile { + +protocol Withdrawing { + func withdraw(amount: Int) -> Bool +} + +final class MoneyPile: Withdrawing { let value: Int var quantity: Int - var nextPile: MoneyPile? + var next: Withdrawing? - init(value: Int, quantity: Int, nextPile: MoneyPile?) { + init(value: Int, quantity: Int, next: Withdrawing?) { self.value = value self.quantity = quantity - self.nextPile = nextPile + self.next = next } - func canWithdraw(amount: Int) -> Bool { + func withdraw(amount: Int) -> Bool { var amount = amount @@ -42,28 +47,29 @@ final class MoneyPile { return true } - if let next = self.nextPile { - return next.canWithdraw(amount: amount) + if let next = self.next { + return next.withdraw(amount: amount) } return false } } -final class ATM { - private var hundred: MoneyPile - private var fifty: MoneyPile - private var twenty: MoneyPile - private var ten: MoneyPile +final class ATM: Withdrawing { - private var startPile: MoneyPile { + private var hundred: Withdrawing + private var fifty: Withdrawing + private var twenty: Withdrawing + private var ten: Withdrawing + + private var startPile: Withdrawing { return self.hundred } - init(hundred: MoneyPile, - fifty: MoneyPile, - twenty: MoneyPile, - ten: MoneyPile) { + init(hundred: Withdrawing, + fifty: Withdrawing, + twenty: Withdrawing, + ten: Withdrawing) { self.hundred = hundred self.fifty = fifty @@ -71,25 +77,20 @@ final class ATM { self.ten = ten } - func canWithdraw(amount: Int) -> String { - return "Can withdraw: \(self.startPile.canWithdraw(amount: amount))" + func withdraw(amount: Int) -> Bool { + return startPile.withdraw(amount: amount) } } /*: ### Usage */ // Create piles of money and link them together 10 < 20 < 50 < 100.** -let ten = MoneyPile(value: 10, quantity: 6, nextPile: nil) -let twenty = MoneyPile(value: 20, quantity: 2, nextPile: ten) -let fifty = MoneyPile(value: 50, quantity: 2, nextPile: twenty) -let hundred = MoneyPile(value: 100, quantity: 1, nextPile: fifty) +let ten = MoneyPile(value: 10, quantity: 6, next: nil) +let twenty = MoneyPile(value: 20, quantity: 2, next: ten) +let fifty = MoneyPile(value: 50, quantity: 2, next: twenty) +let hundred = MoneyPile(value: 100, quantity: 1, next: fifty) // Build ATM. var atm = ATM(hundred: hundred, fifty: fifty, twenty: twenty, ten: ten) -atm.canWithdraw(amount: 310) // Cannot because ATM has only 300 -atm.canWithdraw(amount: 100) // Can withdraw - 1x100 -atm.canWithdraw(amount: 165) // Cannot withdraw because ATM doesn't has bill with value of 5 -atm.canWithdraw(amount: 30) // Can withdraw - 1x20, 2x10 -/*: ->**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Chain-Of-Responsibility) -*/ +atm.withdraw(amount: 310) // Cannot because ATM has only 300 +atm.withdraw(amount: 100) // Can withdraw - 1x100 diff --git a/source/behavioral/command.swift b/source/behavioral/command.swift index 0b1b122..c092a3e 100644 --- a/source/behavioral/command.swift +++ b/source/behavioral/command.swift @@ -10,7 +10,7 @@ protocol DoorCommand { func execute() -> String } -class OpenCommand : DoorCommand { +final class OpenCommand: DoorCommand { let doors:String required init(doors: String) { @@ -22,7 +22,7 @@ class OpenCommand : DoorCommand { } } -class CloseCommand : DoorCommand { +final class CloseCommand: DoorCommand { let doors:String required init(doors: String) { @@ -34,7 +34,7 @@ class CloseCommand : DoorCommand { } } -class HAL9000DoorsOperations { +final class HAL9000DoorsOperations { let openCommand: DoorCommand let closeCommand: DoorCommand diff --git a/source/behavioral/_title.swift b/source/behavioral/header.md similarity index 75% rename from source/behavioral/_title.swift rename to source/behavioral/header.md index 8b29bd2..61e1045 100644 --- a/source/behavioral/_title.swift +++ b/source/behavioral/header.md @@ -1,13 +1,7 @@ -//: Behavioral | -//: [Creational](Creational) | -//: [Structural](Structural) -/*: + Behavioral ========== >In software engineering, behavioral design patterns are design patterns that identify common communication patterns between objects and realize these patterns. By doing so, these patterns increase flexibility in carrying out this communication. > >**Source:** [wikipedia.org](http://en.wikipedia.org/wiki/Behavioral_pattern) -*/ -import Swift -import Foundation diff --git a/source/behavioral/interpreter.swift b/source/behavioral/interpreter.swift index ee520e8..09427b3 100644 --- a/source/behavioral/interpreter.swift +++ b/source/behavioral/interpreter.swift @@ -87,6 +87,3 @@ context.assign(expression: b, value: 1) context.assign(expression: c, value: 3) var result = expression.evaluate(context) -/*: ->**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Interpreter) -*/ diff --git a/source/behavioral/mediator.swift b/source/behavioral/mediator.swift index 8dfc525..07648f5 100644 --- a/source/behavioral/mediator.swift +++ b/source/behavioral/mediator.swift @@ -61,6 +61,4 @@ messagesMediator.add(recipient: user0) messagesMediator.add(recipient: user1) spamMonster(message: "I'd Like to Add you to My Professional Network", worker: messagesMediator) -/*: ->**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Mediator) -*/ + diff --git a/source/behavioral/memento.swift b/source/behavioral/memento.swift index cbf9c93..13b0474 100644 --- a/source/behavioral/memento.swift +++ b/source/behavioral/memento.swift @@ -6,7 +6,7 @@ The memento pattern is used to capture the current state of an object and store ### Example */ -typealias Memento = NSDictionary +typealias Memento = [String: String] /*: Originator */ @@ -31,8 +31,8 @@ struct GameState: MementoConvertible { } init?(memento: Memento) { - guard let mementoChapter = memento[Keys.chapter] as? String, - let mementoWeapon = memento[Keys.weapon] as? String else { + guard let mementoChapter = memento[Keys.chapter], + let mementoWeapon = memento[Keys.weapon] else { return nil } @@ -48,20 +48,20 @@ struct GameState: MementoConvertible { Caretaker */ enum CheckPoint { + + private static let defaults = UserDefaults.standard + static func save(_ state: MementoConvertible, saveName: String) { - let defaults = UserDefaults.standard defaults.set(state.memento, forKey: saveName) defaults.synchronize() } - static func restore(saveName: String) -> Memento? { - let defaults = UserDefaults.standard - - return defaults.object(forKey: saveName) as? Memento + static func restore(saveName: String) -> Any? { + return defaults.object(forKey: saveName) } } /*: - ### Usage +### Usage */ var gameState = GameState(chapter: "Black Mesa Inbound", weapon: "Crowbar") @@ -77,7 +77,7 @@ gameState.chapter = "Office Complex" gameState.weapon = "Crossbow" CheckPoint.save(gameState, saveName: "gameState3") -if let memento = CheckPoint.restore(saveName: "gameState1") { +if let memento = CheckPoint.restore(saveName: "gameState1") as? Memento { let finalState = GameState(memento: memento) dump(finalState) } diff --git a/source/behavioral/observer.swift b/source/behavioral/observer.swift index d54b21a..aec0ac8 100644 --- a/source/behavioral/observer.swift +++ b/source/behavioral/observer.swift @@ -48,6 +48,3 @@ var observerInstance = Observer() var testChambers = TestChambers() testChambers.observer = observerInstance testChambers.testChamberNumber += 1 -/*: ->**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Observer) -*/ diff --git a/source/behavioral/state.swift b/source/behavioral/state.swift index 08b4646..14d84c1 100644 --- a/source/behavioral/state.swift +++ b/source/behavioral/state.swift @@ -25,7 +25,6 @@ final class Context { func changeStateToUnauthorized() { state = UnauthorizedState() } - } protocol State { @@ -57,6 +56,3 @@ userContext.changeStateToAuthorized(userId: "admin") (userContext.isAuthorized, userContext.userId) // now logged in as "admin" userContext.changeStateToUnauthorized() (userContext.isAuthorized, userContext.userId) -/*: ->**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-State) -*/ diff --git a/source/behavioral/strategy.swift b/source/behavioral/strategy.swift index 37480af..f358961 100644 --- a/source/behavioral/strategy.swift +++ b/source/behavioral/strategy.swift @@ -6,42 +6,53 @@ The strategy pattern is used to create an interchangeable family of algorithms f ### Example */ -protocol PrintStrategy { - func print(_ string: String) -> String -} -final class Printer { +struct TestSubject { + let pupilDiameter: Double + let blushResponse: Double + let isOrganic: Bool +} - private let strategy: PrintStrategy +protocol RealnessTesting: AnyObject { + func testRealness(_ testSubject: TestSubject) -> Bool +} - func print(_ string: String) -> String { - return self.strategy.print(string) +final class VoightKampffTest: RealnessTesting { + func testRealness(_ testSubject: TestSubject) -> Bool { + return testSubject.pupilDiameter < 30.0 || testSubject.blushResponse == 0.0 } +} - init(strategy: PrintStrategy) { - self.strategy = strategy +final class GeneticTest: RealnessTesting { + func testRealness(_ testSubject: TestSubject) -> Bool { + return testSubject.isOrganic } } -final class UpperCaseStrategy: PrintStrategy { - func print(_ string: String) -> String { - return string.uppercased() +final class BladeRunner { + private let strategy: RealnessTesting + + init(test: RealnessTesting) { + self.strategy = test } -} -final class LowerCaseStrategy: PrintStrategy { - func print(_ string:String) -> String { - return string.lowercased() + func testIfAndroid(_ testSubject: TestSubject) -> Bool { + return !strategy.testRealness(testSubject) } } -/*: -### Usage -*/ -var lower = Printer(strategy: LowerCaseStrategy()) -lower.print("O tempora, o mores!") -var upper = Printer(strategy: UpperCaseStrategy()) -upper.print("O tempora, o mores!") /*: ->**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Strategy) -*/ + ### Usage + */ + +let rachel = TestSubject(pupilDiameter: 30.2, + blushResponse: 0.3, + isOrganic: false) + +// Deckard is using a traditional test +let deckard = BladeRunner(test: VoightKampffTest()) +let isRachelAndroid = deckard.testIfAndroid(rachel) + +// Gaff is using a very precise method +let gaff = BladeRunner(test: GeneticTest()) +let isDeckardAndroid = gaff.testIfAndroid(rachel) diff --git a/source/behavioral/template.swift b/source/behavioral/template.swift deleted file mode 100644 index f0300a0..0000000 --- a/source/behavioral/template.swift +++ /dev/null @@ -1,77 +0,0 @@ -/*: -🍪 Template ------------ - -The Template Pattern is used when two or more implementations of an -algorithm exist. The template is defined and then built upon with further -variations. Use this method when most (or all) subclasses need to implement -the same behavior. Traditionally, this would be accomplished with abstract -classes and protected methods (as in Java). However in Swift, because -abstract classes don't exist (yet - maybe someday), we need to accomplish -the behavior using interface delegation. - - -### Example -*/ - -protocol ICodeGenerator { - func crossCompile() -} - -protocol IGeneratorPhases { - func collectSource() - func crossCompile() -} - -class CodeGenerator : ICodeGenerator{ - var delegate: IGeneratorPhases - - init(delegate: IGeneratorPhases) { - self.delegate = delegate - } - - private func fetchDataforGeneration(){ - //common implementation - print("fetchDataforGeneration invoked") - } - - //Template method - final func crossCompile() { - fetchDataforGeneration() - delegate.collectSource() - delegate.crossCompile() - } - -} - -class HTMLGeneratorPhases : IGeneratorPhases { - func collectSource() { - print("HTMLGeneratorPhases collectSource() executed") - } - - func crossCompile() { - print("HTMLGeneratorPhases crossCompile() executed") - } -} - -class JSONGeneratorPhases : IGeneratorPhases { - func collectSource() { - print("JSONGeneratorPhases collectSource() executed") - } - - func crossCompile() { - print("JSONGeneratorPhases crossCompile() executed") - } -} - - - -/*: -### Usage -*/ - -let htmlGen : ICodeGenerator = CodeGenerator(delegate: HTMLGeneratorPhases()) -let jsonGen: ICodeGenerator = CodeGenerator(delegate: JSONGeneratorPhases()) - -htmlGen.crossCompile() -jsonGen.crossCompile() diff --git a/source/behavioral/visitor.swift b/source/behavioral/visitor.swift index fdae2eb..d53e409 100644 --- a/source/behavioral/visitor.swift +++ b/source/behavioral/visitor.swift @@ -10,52 +10,48 @@ protocol PlanetVisitor { func visit(planet: PlanetAlderaan) func visit(planet: PlanetCoruscant) func visit(planet: PlanetTatooine) - func visit(planet: MoonJedah) + func visit(planet: MoonJedha) } protocol Planet { func accept(visitor: PlanetVisitor) } -class MoonJedah: Planet { +final class MoonJedha: Planet { func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) } } -class PlanetAlderaan: Planet { +final class PlanetAlderaan: Planet { func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) } } -class PlanetCoruscant: Planet { +final class PlanetCoruscant: Planet { func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) } } -class PlanetTatooine: Planet { +final class PlanetTatooine: Planet { func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) } } - - -class NameVisitor: PlanetVisitor { +final class NameVisitor: PlanetVisitor { var name = "" func visit(planet: PlanetAlderaan) { name = "Alderaan" } func visit(planet: PlanetCoruscant) { name = "Coruscant" } func visit(planet: PlanetTatooine) { name = "Tatooine" } - func visit(planet: MoonJedah) { name = "Jedah" } + func visit(planet: MoonJedha) { name = "Jedha" } } /*: ### Usage */ -let planets: [Planet] = [PlanetAlderaan(), PlanetCoruscant(), PlanetTatooine(), MoonJedah()] +let planets: [Planet] = [PlanetAlderaan(), PlanetCoruscant(), PlanetTatooine(), MoonJedha()] let names = planets.map { (planet: Planet) -> String in let visitor = NameVisitor() planet.accept(visitor: visitor) - return visitor.name + + return visitor.name } names -/*: ->**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Visitor) -*/ diff --git a/source/contents.md b/source/contents.md new file mode 100644 index 0000000..8503238 --- /dev/null +++ b/source/contents.md @@ -0,0 +1,6 @@ + +## Table of Contents + +* [Behavioral](Behavioral) +* [Creational](Creational) +* [Structural](Structural) diff --git a/source/creational/abstract_factory.swift b/source/creational/abstract_factory.swift index f279ef7..16d2899 100644 --- a/source/creational/abstract_factory.swift +++ b/source/creational/abstract_factory.swift @@ -6,65 +6,56 @@ The abstract factory pattern is used to provide a client with a set of related o The "family" of objects created by the factory are determined at run-time. ### Example -*/ -/*: + Protocols */ -protocol Decimal { - func stringValue() -> String - // factory - static func make(string : String) -> Decimal + +protocol BurgerDescribing { + var ingredients: [String] { get } } -typealias NumberFactory = (String) -> Decimal +struct CheeseBurger: BurgerDescribing { + let ingredients: [String] +} -// Number implementations with factory methods +protocol BurgerMaking { + func make() -> BurgerDescribing +} -struct NextStepNumber: Decimal { - private var nextStepNumber: NSNumber +// Number implementations with factory methods - func stringValue() -> String { return nextStepNumber.stringValue } - - // factory - static func make(string: String) -> Decimal { - return NextStepNumber(nextStepNumber: NSNumber(value: (string as NSString).longLongValue)) +final class BigKahunaBurger: BurgerMaking { + func make() -> BurgerDescribing { + return CheeseBurger(ingredients: ["Cheese", "Burger", "Lettuce", "Tomato"]) } } -struct SwiftNumber : Decimal { - private var swiftInt: Int - - func stringValue() -> String { return "\(swiftInt)" } - - // factory - static func make(string: String) -> Decimal { - return SwiftNumber(swiftInt:(string as NSString).integerValue) +final class JackInTheBox: BurgerMaking { + func make() -> BurgerDescribing { + return CheeseBurger(ingredients: ["Cheese", "Burger", "Tomato", "Onions"]) } } + /*: Abstract factory */ -enum NumberType { - case nextStep, swift -} -enum NumberHelper { - static func factory(for type: NumberType) -> NumberFactory { - switch type { - case .nextStep: - return NextStepNumber.make - case .swift: - return SwiftNumber.make +enum BurgerFactoryType: BurgerMaking { + + case bigKahuna + case jackInTheBox + + func make() -> BurgerDescribing { + switch self { + case .bigKahuna: + return BigKahunaBurger().make() + case .jackInTheBox: + return JackInTheBox().make() } } } /*: ### Usage */ -let factoryOne = NumberHelper.factory(for: .nextStep) -let numberOne = factoryOne("1") -numberOne.stringValue() - -let factoryTwo = NumberHelper.factory(for: .swift) -let numberTwo = factoryTwo("2") -numberTwo.stringValue() +let bigKahuna = BurgerFactoryType.bigKahuna.make() +let jackInTheBox = BurgerFactoryType.jackInTheBox.make() diff --git a/source/creational/builder.swift b/source/creational/builder.swift index 7bb27f2..139139a 100644 --- a/source/creational/builder.swift +++ b/source/creational/builder.swift @@ -7,7 +7,7 @@ An external class controls the construction algorithm. ### Example */ -class DeathStarBuilder { +final class DeathStarBuilder { var x: Double? var y: Double? @@ -51,6 +51,3 @@ let empire = DeathStarBuilder { builder in } let deathStar = DeathStar(builder:empire) -/*: ->**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Builder) -*/ diff --git a/source/creational/factory.swift b/source/creational/factory.swift index cc04387..aeee853 100644 --- a/source/creational/factory.swift +++ b/source/creational/factory.swift @@ -6,42 +6,45 @@ The factory pattern is used to replace class constructors, abstracting the proce ### Example */ -protocol Currency { - func symbol() -> String - func code() -> String +protocol CurrencyDescribing { + var symbol: String { get } + var code: String { get } } -class Euro : Currency { - func symbol() -> String { +final class Euro: CurrencyDescribing { + var symbol: String { return "€" } - func code() -> String { + var code: String { return "EUR" } } -class UnitedStatesDolar : Currency { - func symbol() -> String { +final class UnitedStatesDolar: CurrencyDescribing { + var symbol: String { return "$" } - func code() -> String { + var code: String { return "USD" } } enum Country { - case unitedStates, spain, uk, greece + case unitedStates + case spain + case uk + case greece } enum CurrencyFactory { - static func currency(for country:Country) -> Currency? { + static func currency(for country: Country) -> CurrencyDescribing? { switch country { - case .spain, .greece : + case .spain, .greece: return Euro() - case .unitedStates : + case .unitedStates: return UnitedStatesDolar() default: return nil @@ -54,7 +57,7 @@ enum CurrencyFactory { */ let noCurrencyCode = "No Currency Code Available" -CurrencyFactory.currency(for: .greece)?.code() ?? noCurrencyCode -CurrencyFactory.currency(for: .spain)?.code() ?? noCurrencyCode -CurrencyFactory.currency(for: .unitedStates)?.code() ?? noCurrencyCode -CurrencyFactory.currency(for: .uk)?.code() ?? noCurrencyCode +CurrencyFactory.currency(for: .greece)?.code ?? noCurrencyCode +CurrencyFactory.currency(for: .spain)?.code ?? noCurrencyCode +CurrencyFactory.currency(for: .unitedStates)?.code ?? noCurrencyCode +CurrencyFactory.currency(for: .uk)?.code ?? noCurrencyCode diff --git a/source/creational/_title.swift b/source/creational/header.md similarity index 80% rename from source/creational/_title.swift rename to source/creational/header.md index 154c33a..1684668 100644 --- a/source/creational/_title.swift +++ b/source/creational/header.md @@ -1,13 +1,7 @@ -//: [Behavioral](Behavioral) | -//: Creational | -//: [Structural](Structural) -/*: + Creational ========== > In software engineering, creational design patterns are design patterns that deal with object creation mechanisms, trying to create objects in a manner suitable to the situation. The basic form of object creation could result in design problems or added complexity to the design. Creational design patterns solve this problem by somehow controlling this object creation. > >**Source:** [wikipedia.org](http://en.wikipedia.org/wiki/Creational_pattern) -*/ -import Swift -import Foundation diff --git a/source/creational/prototype.swift b/source/creational/prototype.swift index e19b974..7840489 100644 --- a/source/creational/prototype.swift +++ b/source/creational/prototype.swift @@ -7,31 +7,29 @@ This practise is particularly useful when the construction of a new object is in ### Example */ -class ChungasRevengeDisplay { - var name: String? - let font: String +struct MoonWorker { - init(font: String) { - self.font = font + let name: String + var health: Int = 100 + + init(name: String) { + self.name = name } - func clone() -> ChungasRevengeDisplay { - return ChungasRevengeDisplay(font:self.font) + func clone() -> MoonWorker { + return MoonWorker(name: name) } } /*: ### Usage */ -let Prototype = ChungasRevengeDisplay(font:"GotanProject") +let prototype = MoonWorker(name: "Sam Bell") -let Philippe = Prototype.clone() -Philippe.name = "Philippe" +var bell1 = prototype.clone() +bell1.health = 12 -let Christoph = Prototype.clone() -Christoph.name = "Christoph" +var bell2 = prototype.clone() +bell2.health = 23 -let Eduardo = Prototype.clone() -Eduardo.name = "Eduardo" -/*: ->**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Prototype) -*/ +var bell3 = prototype.clone() +bell3.health = 0 diff --git a/source/creational/singleton.swift b/source/creational/singleton.swift index 193118a..539bca5 100644 --- a/source/creational/singleton.swift +++ b/source/creational/singleton.swift @@ -8,8 +8,9 @@ There are very few applications, do not overuse this pattern! ### Example: */ -class DeathStarSuperlaser { - static let sharedInstance = DeathStarSuperlaser() +final class ElonMusk { + + static let shared = ElonMusk() private init() { // Private initialization to ensure just one instance is created. @@ -18,4 +19,4 @@ class DeathStarSuperlaser { /*: ### Usage: */ -let laser = DeathStarSuperlaser.sharedInstance +let elon = ElonMusk.shared // There is only one Elon Musk folks. diff --git a/source/endComment b/source/endComment new file mode 100644 index 0000000..9f82b4e --- /dev/null +++ b/source/endComment @@ -0,0 +1,2 @@ + +*/ \ No newline at end of file diff --git a/source/endSwiftCode b/source/endSwiftCode new file mode 100644 index 0000000..7dc72a8 --- /dev/null +++ b/source/endSwiftCode @@ -0,0 +1,2 @@ +``` + diff --git a/source/footer.swift b/source/footer.md similarity index 94% rename from source/footer.swift rename to source/footer.md index 566efc7..21002da 100644 --- a/source/footer.swift +++ b/source/footer.md @@ -1,8 +1,5 @@ -/*: Info ==== 📖 Descriptions from: [Gang of Four Design Patterns Reference Sheet](http://www.blackwasp.co.uk/GangOfFour.aspx) - -*/ diff --git a/source/header.swift b/source/header.swift deleted file mode 100644 index bfcab55..0000000 --- a/source/header.swift +++ /dev/null @@ -1,16 +0,0 @@ - -Design Patterns implemented in Swift 3.0 -======================================== -A short cheat-sheet with Xcode 8.2 Playground ([Design-Patterns.playground.zip](https://raw.githubusercontent.com/ochococo/Design-Patterns-In-Swift/master/Design-Patterns.playground.zip)). - -👷 Project maintained by: [@nsmeme](http://twitter.com/nsmeme) (Oktawian Chojnacki) - -🚀 How to generate README, Playground and zip from source: [GENERATE.md](https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/GENERATE.md) - -## Table of Contents - -* [Behavioral](#behavioral) -* [Creational](#creational) -* [Structural](#structural) - -*/ diff --git a/source/imports.swift b/source/imports.swift new file mode 100644 index 0000000..350c82f --- /dev/null +++ b/source/imports.swift @@ -0,0 +1,2 @@ + +import Foundation diff --git a/source/startComment b/source/startComment new file mode 100644 index 0000000..a23f02a --- /dev/null +++ b/source/startComment @@ -0,0 +1 @@ +/*: diff --git a/source/startSwiftCode b/source/startSwiftCode new file mode 100644 index 0000000..591b2be --- /dev/null +++ b/source/startSwiftCode @@ -0,0 +1,3 @@ + + +```swift \ No newline at end of file diff --git a/source/structural/adapter.swift b/source/structural/adapter.swift index bc8efa6..3a99081 100644 --- a/source/structural/adapter.swift +++ b/source/structural/adapter.swift @@ -6,18 +6,18 @@ The adapter pattern is used to provide a link between two otherwise incompatible ### Example */ -protocol OlderDeathStarSuperLaserAiming { - var angleV: NSNumber {get} - var angleH: NSNumber {get} +protocol NewDeathStarSuperLaserAiming { + var angleV: Double { get } + var angleH: Double { get } } /*: **Adaptee** */ -struct DeathStarSuperlaserTarget { - let angleHorizontal: Double - let angleVertical: Double +struct OldDeathStarSuperlaserTarget { + let angleHorizontal: Float + let angleVertical: Float - init(angleHorizontal:Double, angleVertical:Double) { + init(angleHorizontal: Float, angleVertical: Float) { self.angleHorizontal = angleHorizontal self.angleVertical = angleVertical } @@ -25,29 +25,27 @@ struct DeathStarSuperlaserTarget { /*: **Adapter** */ -struct OldDeathStarSuperlaserTarget : OlderDeathStarSuperLaserAiming { - private let target : DeathStarSuperlaserTarget +struct NewDeathStarSuperlaserTarget: NewDeathStarSuperLaserAiming { - var angleV:NSNumber { - return NSNumber(value: target.angleVertical) + private let target: OldDeathStarSuperlaserTarget + + var angleV: Double { + return Double(target.angleVertical) } - var angleH:NSNumber { - return NSNumber(value: target.angleHorizontal) + var angleH: Double { + return Double(target.angleHorizontal) } - init(_ target:DeathStarSuperlaserTarget) { + init(_ target: OldDeathStarSuperlaserTarget) { self.target = target } } /*: ### Usage */ -let target = DeathStarSuperlaserTarget(angleHorizontal: 14.0, angleVertical: 12.0) -let oldFormat = OldDeathStarSuperlaserTarget(target) +let target = OldDeathStarSuperlaserTarget(angleHorizontal: 14.0, angleVertical: 12.0) +let newFormat = NewDeathStarSuperlaserTarget(target) -oldFormat.angleH -oldFormat.angleV -/*: ->**Further Examples:** [Design Patterns in Swift](https://github.com/kingreza/Swift-Adapter) -*/ +newFormat.angleH +newFormat.angleV diff --git a/source/structural/bridge.swift b/source/structural/bridge.swift index e5972d6..2384c7e 100644 --- a/source/structural/bridge.swift +++ b/source/structural/bridge.swift @@ -7,7 +7,7 @@ The bridge pattern is used to separate the abstract elements of a class from the ### Example */ protocol Switch { - var appliance: Appliance {get set} + var appliance: Appliance { get set } func turnOn() } @@ -15,7 +15,7 @@ protocol Appliance { func run() } -class RemoteControl: Switch { +final class RemoteControl: Switch { var appliance: Appliance func turnOn() { @@ -27,13 +27,13 @@ class RemoteControl: Switch { } } -class TV: Appliance { +final class TV: Appliance { func run() { print("tv turned on"); } } -class VacuumCleaner: Appliance { +final class VacuumCleaner: Appliance { func run() { print("vacuum cleaner turned on") } @@ -41,8 +41,8 @@ class VacuumCleaner: Appliance { /*: ### Usage */ -var tvRemoteControl = RemoteControl(appliance: TV()) +let tvRemoteControl = RemoteControl(appliance: TV()) tvRemoteControl.turnOn() -var fancyVacuumCleanerRemoteControl = RemoteControl(appliance: VacuumCleaner()) +let fancyVacuumCleanerRemoteControl = RemoteControl(appliance: VacuumCleaner()) fancyVacuumCleanerRemoteControl.turnOn() diff --git a/source/structural/composite.swift b/source/structural/composite.swift index fea9bd5..522cd7c 100644 --- a/source/structural/composite.swift +++ b/source/structural/composite.swift @@ -5,8 +5,7 @@ The composite pattern is used to create hierarchical, recursive tree structures of related objects where any element of the structure may be accessed and utilised in a standard manner. ### Example -*/ -/*: + Component */ protocol Shape { @@ -15,13 +14,13 @@ protocol Shape { /*: Leafs */ -final class Square : Shape { +final class Square: Shape { func draw(fillColor: String) { print("Drawing a Square with color \(fillColor)") } } -final class Circle : Shape { +final class Circle: Shape { func draw(fillColor: String) { print("Drawing a circle with color \(fillColor)") } @@ -30,10 +29,11 @@ final class Circle : Shape { /*: Composite */ -final class Whiteboard : Shape { - lazy var shapes = [Shape]() +final class Whiteboard: Shape { + + private lazy var shapes = [Shape]() - init(_ shapes:Shape...) { + init(_ shapes: Shape...) { self.shapes = shapes } diff --git a/source/structural/decorator.swift b/source/structural/decorator.swift index 29acf49..c531d1e 100644 --- a/source/structural/decorator.swift +++ b/source/structural/decorator.swift @@ -7,71 +7,56 @@ This provides a flexible alternative to using inheritance to modify behaviour. ### Example */ -protocol Coffee { - func getCost() -> Double - func getIngredients() -> String +protocol CostHaving { + var cost: Double { get } } -class SimpleCoffee: Coffee { - func getCost() -> Double { - return 1.0 - } - - func getIngredients() -> String { - return "Coffee" - } +protocol IngredientsHaving { + var ingredients: [String] { get } } -class CoffeeDecorator: Coffee { - private let decoratedCoffee: Coffee - fileprivate let ingredientSeparator: String = ", " +typealias BeverageDataHaving = CostHaving & IngredientsHaving - required init(decoratedCoffee: Coffee) { - self.decoratedCoffee = decoratedCoffee - } - - func getCost() -> Double { - return decoratedCoffee.getCost() - } +struct SimpleCoffee: BeverageDataHaving { + let cost: Double = 1.0 + let ingredients = ["Water", "Coffee"] +} - func getIngredients() -> String { - return decoratedCoffee.getIngredients() - } +protocol BeverageHaving: BeverageDataHaving { + var beverage: BeverageDataHaving { get } } -final class Milk: CoffeeDecorator { - required init(decoratedCoffee: Coffee) { - super.init(decoratedCoffee: decoratedCoffee) - } +struct Milk: BeverageHaving { - override func getCost() -> Double { - return super.getCost() + 0.5 + let beverage: BeverageDataHaving + + var cost: Double { + return beverage.cost + 0.5 } - override func getIngredients() -> String { - return super.getIngredients() + ingredientSeparator + "Milk" + var ingredients: [String] { + return beverage.ingredients + ["Milk"] } } -final class WhipCoffee: CoffeeDecorator { - required init(decoratedCoffee: Coffee) { - super.init(decoratedCoffee: decoratedCoffee) - } +struct WhipCoffee: BeverageHaving { + + let beverage: BeverageDataHaving - override func getCost() -> Double { - return super.getCost() + 0.7 + var cost: Double { + return beverage.cost + 0.5 } - override func getIngredients() -> String { - return super.getIngredients() + ingredientSeparator + "Whip" + var ingredients: [String] { + return beverage.ingredients + ["Whip"] } } /*: ### Usage: */ -var someCoffee: Coffee = SimpleCoffee() -print("Cost : \(someCoffee.getCost()); Ingredients: \(someCoffee.getIngredients())") -someCoffee = Milk(decoratedCoffee: someCoffee) -print("Cost : \(someCoffee.getCost()); Ingredients: \(someCoffee.getIngredients())") -someCoffee = WhipCoffee(decoratedCoffee: someCoffee) -print("Cost : \(someCoffee.getCost()); Ingredients: \(someCoffee.getIngredients())") +var someCoffee: BeverageDataHaving = SimpleCoffee() +print("Cost: \(someCoffee.cost); Ingredients: \(someCoffee.ingredients)") +someCoffee = Milk(beverage: someCoffee) +print("Cost: \(someCoffee.cost); Ingredients: \(someCoffee.ingredients)") +someCoffee = WhipCoffee(beverage: someCoffee) +print("Cost: \(someCoffee.cost); Ingredients: \(someCoffee.ingredients)") diff --git a/source/structural/facade.swift b/source/structural/facade.swift index b873dd0..1147d57 100644 --- a/source/structural/facade.swift +++ b/source/structural/facade.swift @@ -6,22 +6,31 @@ The facade pattern is used to define a simplified interface to a more complex su ### Example */ -enum Eternal { +final class Defaults { - static func set(_ object: Any, forKey defaultName: String) { - let defaults: UserDefaults = UserDefaults.standard - defaults.set(object, forKey:defaultName) - defaults.synchronize() - } + private let defaults: UserDefaults - static func object(forKey key: String) -> AnyObject! { - let defaults: UserDefaults = UserDefaults.standard - return defaults.object(forKey: key) as AnyObject! + init(defaults: UserDefaults = .standard) { + self.defaults = defaults } + subscript(key: String) -> String? { + get { + return defaults.string(forKey: key) + } + + set { + defaults.set(newValue, forKey: key) + } + } } /*: ### Usage */ -Eternal.set("Disconnect me. I’d rather be nothing", forKey:"Bishop") -Eternal.object(forKey: "Bishop") +let storage = Defaults() + +// Store +storage["Bishop"] = "Disconnect me. I’d rather be nothing" + +// Read +storage["Bishop"] diff --git a/source/structural/flyweight.swift b/source/structural/flyweight.swift index 02e4efd..3a2d944 100644 --- a/source/structural/flyweight.swift +++ b/source/structural/flyweight.swift @@ -3,25 +3,21 @@ The flyweight pattern is used to minimize memory usage or computational expenses by sharing as much as possible with other similar objects. ### Example */ -// Instances of CoffeeFlavour will be the Flyweights -final class SpecialityCoffee: CustomStringConvertible { - var origin: String - var description: String { - get { - return origin - } - } +// Instances of SpecialityCoffee will be the Flyweights +struct SpecialityCoffee { + let origin: String +} - init(origin: String) { - self.origin = origin - } +protocol CoffeeSearching { + func search(origin: String) -> SpecialityCoffee? } -// Menu acts as a factory and cache for CoffeeFlavour flyweight objects -final class Menu { +// Menu acts as a factory and cache for SpecialityCoffee flyweight objects +final class Menu: CoffeeSearching { + private var coffeeAvailable: [String: SpecialityCoffee] = [:] - func lookup(origin: String) -> SpecialityCoffee? { + func search(origin: String) -> SpecialityCoffee? { if coffeeAvailable.index(forKey: origin) == nil { coffeeAvailable[origin] = SpecialityCoffee(origin: origin) } @@ -32,10 +28,14 @@ final class Menu { final class CoffeeShop { private var orders: [Int: SpecialityCoffee] = [:] - private var menu = Menu() + private let menu: CoffeeSearching + + init(menu: CoffeeSearching) { + self.menu = menu + } func takeOrder(origin: String, table: Int) { - orders[table] = menu.lookup(origin: origin) + orders[table] = menu.search(origin: origin) } func serve() { @@ -47,7 +47,7 @@ final class CoffeeShop { /*: ### Usage */ -let coffeeShop = CoffeeShop() +let coffeeShop = CoffeeShop(menu: Menu()) coffeeShop.takeOrder(origin: "Yirgacheffe, Ethiopia", table: 1) coffeeShop.takeOrder(origin: "Buziraguhindwa, Burundi", table: 3) diff --git a/source/structural/_title.swift b/source/structural/header.md similarity index 69% rename from source/structural/_title.swift rename to source/structural/header.md index a944c72..67cdc66 100644 --- a/source/structural/_title.swift +++ b/source/structural/header.md @@ -1,13 +1,7 @@ -//: [Behavioral](Behavioral) | -//: [Creational](Creational) | -//: Structural -/*: + Structural ========== >In software engineering, structural design patterns are design patterns that ease the design by identifying a simple way to realize relationships between entities. > >**Source:** [wikipedia.org](http://en.wikipedia.org/wiki/Structural_pattern) -*/ -import Swift -import Foundation diff --git a/source/structural/protection_proxy.swift b/source/structural/protection_proxy.swift index bde142d..f012f47 100644 --- a/source/structural/protection_proxy.swift +++ b/source/structural/protection_proxy.swift @@ -7,23 +7,23 @@ Protection proxy is restricting access. ### Example */ -protocol DoorOperator { +protocol DoorOpening { func open(doors: String) -> String } -class HAL9000 : DoorOperator { +final class HAL9000: DoorOpening { func open(doors: String) -> String { return ("HAL9000: Affirmative, Dave. I read you. Opened \(doors).") } } -class CurrentComputer : DoorOperator { +final class CurrentComputer: DoorOpening { private var computer: HAL9000! func authenticate(password: String) -> Bool { guard password == "pass" else { - return false; + return false } computer = HAL9000() diff --git a/source/structural/virtual_proxy.swift b/source/structural/virtual_proxy.swift index 9d59035..9a02414 100644 --- a/source/structural/virtual_proxy.swift +++ b/source/structural/virtual_proxy.swift @@ -11,13 +11,14 @@ protocol HEVSuitMedicalAid { func administerMorphine() -> String } -class HEVSuit : HEVSuitMedicalAid { +final class HEVSuit: HEVSuitMedicalAid { func administerMorphine() -> String { return "Morphine administered." } } -class HEVSuitHumanInterface : HEVSuitMedicalAid { +final class HEVSuitHumanInterface: HEVSuitMedicalAid { + lazy private var physicalSuit: HEVSuit = HEVSuit() func administerMorphine() -> String { From f74a7b9002577ccf743ca5ef120bd4da0d794125 Mon Sep 17 00:00:00 2001 From: Oktawian Chojnacki Date: Tue, 29 Oct 2019 14:53:56 +0100 Subject: [PATCH 20/66] You can now sponsor me via GitHub! --- .github/FUNDING.yml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..dbf5acd --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,3 @@ +# These are supported funding model platforms + +github: ochococo From 733da3feaba79e7e4e5c8cbdadfbb834342ea347 Mon Sep 17 00:00:00 2001 From: Oktawian Chojnacki Date: Sat, 2 Nov 2019 17:43:14 +0100 Subject: [PATCH 21/66] Please consider supporting my work --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c214421..73cb316 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,10 @@ A short cheat-sheet with Xcode 10.2 Playground ([Design-Patterns.playground.zip] 👷 Project maintained by: [@nsmeme](http://twitter.com/nsmeme) (Oktawian Chojnacki) -🚀 How to generate README, Playground and zip from source: [GENERATE.md](https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/GENERATE.md) +❤️ Please consider supporting my work, [become my Sponsor!](https://github.com/sponsors/ochococo) 🙏 + + +How to generate README, Playground and zip from source: [GENERATE.md](https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/GENERATE.md) ```swift From d5dab21ebcd558b72338f9e66620ec93a783914d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=85=B4=E5=BD=AC=5FBinboy?= Date: Fri, 13 Mar 2020 16:03:53 +0800 Subject: [PATCH 22/66] Clean up useless files --- .../Pages/Untitled Page 2.xcplaygroundpage/Contents.swift | 7 ------- .../Pages/Untitled Page.xcplaygroundpage/Contents.swift | 3 --- .../Untitled Page.xcplaygroundpage/timeline.xctimeline | 6 ------ MyPlayground.playground/contents.xcplayground | 4 ---- 4 files changed, 20 deletions(-) delete mode 100644 MyPlayground.playground/Pages/Untitled Page 2.xcplaygroundpage/Contents.swift delete mode 100644 MyPlayground.playground/Pages/Untitled Page.xcplaygroundpage/Contents.swift delete mode 100644 MyPlayground.playground/Pages/Untitled Page.xcplaygroundpage/timeline.xctimeline delete mode 100644 MyPlayground.playground/contents.xcplayground diff --git a/MyPlayground.playground/Pages/Untitled Page 2.xcplaygroundpage/Contents.swift b/MyPlayground.playground/Pages/Untitled Page 2.xcplaygroundpage/Contents.swift deleted file mode 100644 index 854a033..0000000 --- a/MyPlayground.playground/Pages/Untitled Page 2.xcplaygroundpage/Contents.swift +++ /dev/null @@ -1,7 +0,0 @@ -//: [Previous](@previous) - -import Foundation - -var str = "Hello, playground" - -//: [Next](@next) diff --git a/MyPlayground.playground/Pages/Untitled Page.xcplaygroundpage/Contents.swift b/MyPlayground.playground/Pages/Untitled Page.xcplaygroundpage/Contents.swift deleted file mode 100644 index 49c1ff6..0000000 --- a/MyPlayground.playground/Pages/Untitled Page.xcplaygroundpage/Contents.swift +++ /dev/null @@ -1,3 +0,0 @@ -import UIKit - -var str = "Hello, playground" diff --git a/MyPlayground.playground/Pages/Untitled Page.xcplaygroundpage/timeline.xctimeline b/MyPlayground.playground/Pages/Untitled Page.xcplaygroundpage/timeline.xctimeline deleted file mode 100644 index bf468af..0000000 --- a/MyPlayground.playground/Pages/Untitled Page.xcplaygroundpage/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/MyPlayground.playground/contents.xcplayground b/MyPlayground.playground/contents.xcplayground deleted file mode 100644 index 9f5f2f4..0000000 --- a/MyPlayground.playground/contents.xcplayground +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file From 8f7636cc6c023d34221b16cc28e375544d4cfdbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=85=B4=E5=BD=AC=5FBinboy?= Date: Fri, 13 Mar 2020 16:08:42 +0800 Subject: [PATCH 23/66] Add a table of contents for convenience. * just add for generating readme * not mess up the playground --- README.md | 16 ++++++++++++++++ generate-playground.sh | 1 + source/contentsReadme.md | 16 ++++++++++++++++ 3 files changed, 33 insertions(+) create mode 100644 source/contentsReadme.md diff --git a/README.md b/README.md index 73cb316..3d9dc60 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,22 @@ print("Welcome!") ``` +## Table of Contents + +| [Behavioral](#behavioral) | [Creational](#creational) | [Structural](#structural) | +| ------------------------------------------------------ | ---------------------------------------- | ---------------------------------------- | +| [🐝 Chain Of Responsibility](#-chain-of-responsibility) | [🌰 Abstract Factory](#-abstract-factory) | [🔌 Adapter](#-adapter) | +| [👫 Command](#-command) | [👷 Builder](#-builder) | [🌉 Bridge](#-bridge) | +| [🎶 Interpreter](#-interpreter) | [🏭 Factory Method](#-factory-method) | [🌿 Composite](#-composite) | +| [🍫 Iterator](#-iterator) | [🃏 Prototype](#-prototype) | [🍧 Decorator](#-decorator) | +| [💐 Mediator](#-mediator) | [💍 Singleton](#-singleton) | [🎁 Façade](#-fa-ade) | +| [💾 Memento](#-memento) | | [🍃 Flyweight](#-flyweight) | +| [👓 Observer](#-observer) | | [☔ Protection Proxy](#-protection-proxy) | +| [🐉 State](#-state) | | [🍬 Virtual Proxy](#-virtual-proxy) | +| [💡 Strategy](#-strategy) | | | +| [🏃 Visitor](#-visitor) | | | + + Behavioral ========== diff --git a/generate-playground.sh b/generate-playground.sh index 12878a3..9e87220 100755 --- a/generate-playground.sh +++ b/generate-playground.sh @@ -57,6 +57,7 @@ zip -r -X Design-Patterns.playground.zip ./Design-Patterns.playground echo "" > README.md readme Index +cat source/contentsReadme.md >> README.md readme Behavioral readme Creational readme Structural diff --git a/source/contentsReadme.md b/source/contentsReadme.md new file mode 100644 index 0000000..7a92ac8 --- /dev/null +++ b/source/contentsReadme.md @@ -0,0 +1,16 @@ + +## Table of Contents + +| [Behavioral](#behavioral) | [Creational](#creational) | [Structural](#structural) | +| ------------------------------------------------------ | ---------------------------------------- | ---------------------------------------- | +| [🐝 Chain Of Responsibility](#-chain-of-responsibility) | [🌰 Abstract Factory](#-abstract-factory) | [🔌 Adapter](#-adapter) | +| [👫 Command](#-command) | [👷 Builder](#-builder) | [🌉 Bridge](#-bridge) | +| [🎶 Interpreter](#-interpreter) | [🏭 Factory Method](#-factory-method) | [🌿 Composite](#-composite) | +| [🍫 Iterator](#-iterator) | [🃏 Prototype](#-prototype) | [🍧 Decorator](#-decorator) | +| [💐 Mediator](#-mediator) | [💍 Singleton](#-singleton) | [🎁 Façade](#-fa-ade) | +| [💾 Memento](#-memento) | | [🍃 Flyweight](#-flyweight) | +| [👓 Observer](#-observer) | | [☔ Protection Proxy](#-protection-proxy) | +| [🐉 State](#-state) | | [🍬 Virtual Proxy](#-virtual-proxy) | +| [💡 Strategy](#-strategy) | | | +| [🏃 Visitor](#-visitor) | | | + From 5e2f837a231d915b6ac6d8b76e344ee8beeae07a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=85=B4=E5=BD=AC=5FBinboy?= Date: Fri, 13 Mar 2020 21:17:24 +0800 Subject: [PATCH 24/66] Seperate source and script to translate for cn --- generate-playground-cn.sh | 64 +++++++++++++ source-cn/Index/header.md | 9 ++ source-cn/Index/welcome.swift | 2 + .../behavioral/chain_of_responsibility.swift | 96 +++++++++++++++++++ source-cn/behavioral/command.swift | 61 ++++++++++++ source-cn/behavioral/header.md | 7 ++ source-cn/behavioral/interpreter.swift | 89 +++++++++++++++++ source-cn/behavioral/iterator.swift | 44 +++++++++ source-cn/behavioral/mediator.swift | 64 +++++++++++++ source-cn/behavioral/memento.swift | 83 ++++++++++++++++ source-cn/behavioral/observer.swift | 50 ++++++++++ source-cn/behavioral/state.swift | 58 +++++++++++ source-cn/behavioral/strategy.swift | 58 +++++++++++ source-cn/behavioral/visitor.swift | 57 +++++++++++ source-cn/contents.md | 6 ++ source-cn/contentsReadme.md | 16 ++++ source-cn/creational/abstract_factory.swift | 61 ++++++++++++ source-cn/creational/builder.swift | 53 ++++++++++ source-cn/creational/factory.swift | 63 ++++++++++++ source-cn/creational/header.md | 7 ++ source-cn/creational/prototype.swift | 35 +++++++ source-cn/creational/singleton.swift | 22 +++++ source-cn/endComment | 2 + source-cn/endSwiftCode | 2 + source-cn/footer.md | 5 + source-cn/imports.swift | 2 + source-cn/startComment | 1 + source-cn/startSwiftCode | 3 + source-cn/structural/adapter.swift | 51 ++++++++++ source-cn/structural/bridge.swift | 48 ++++++++++ source-cn/structural/composite.swift | 50 ++++++++++ source-cn/structural/decorator.swift | 62 ++++++++++++ source-cn/structural/facade.swift | 36 +++++++ source-cn/structural/flyweight.swift | 55 +++++++++++ source-cn/structural/header.md | 7 ++ source-cn/structural/protection_proxy.swift | 52 ++++++++++ source-cn/structural/virtual_proxy.swift | 32 +++++++ 37 files changed, 1413 insertions(+) create mode 100755 generate-playground-cn.sh create mode 100644 source-cn/Index/header.md create mode 100644 source-cn/Index/welcome.swift create mode 100644 source-cn/behavioral/chain_of_responsibility.swift create mode 100644 source-cn/behavioral/command.swift create mode 100644 source-cn/behavioral/header.md create mode 100644 source-cn/behavioral/interpreter.swift create mode 100644 source-cn/behavioral/iterator.swift create mode 100644 source-cn/behavioral/mediator.swift create mode 100644 source-cn/behavioral/memento.swift create mode 100644 source-cn/behavioral/observer.swift create mode 100644 source-cn/behavioral/state.swift create mode 100644 source-cn/behavioral/strategy.swift create mode 100644 source-cn/behavioral/visitor.swift create mode 100644 source-cn/contents.md create mode 100644 source-cn/contentsReadme.md create mode 100644 source-cn/creational/abstract_factory.swift create mode 100644 source-cn/creational/builder.swift create mode 100644 source-cn/creational/factory.swift create mode 100644 source-cn/creational/header.md create mode 100644 source-cn/creational/prototype.swift create mode 100644 source-cn/creational/singleton.swift create mode 100644 source-cn/endComment create mode 100644 source-cn/endSwiftCode create mode 100644 source-cn/footer.md create mode 100644 source-cn/imports.swift create mode 100644 source-cn/startComment create mode 100644 source-cn/startSwiftCode create mode 100644 source-cn/structural/adapter.swift create mode 100644 source-cn/structural/bridge.swift create mode 100644 source-cn/structural/composite.swift create mode 100644 source-cn/structural/decorator.swift create mode 100644 source-cn/structural/facade.swift create mode 100644 source-cn/structural/flyweight.swift create mode 100644 source-cn/structural/header.md create mode 100644 source-cn/structural/protection_proxy.swift create mode 100644 source-cn/structural/virtual_proxy.swift diff --git a/generate-playground-cn.sh b/generate-playground-cn.sh new file mode 100755 index 0000000..9e87220 --- /dev/null +++ b/generate-playground-cn.sh @@ -0,0 +1,64 @@ +#!/bin/bash + +# Note: I think this part is absolute garbage but it's a snapshot of my current skills with Bash. +# Would love to rewrite it in Swift soon. + +combineSwift() { + cat source/startComment > $2 + cat $1/header.md >> $2 + cat source/contents.md >> $2 + cat source/endComment >> $2 + cat source/imports.swift >> $2 + cat $1/*.swift >> $2 + { rm $2 && awk '{gsub("\\*//\\*:", "", $0); print}' > $2; } < $2 +} + +move() { + mv $1.swift Design-Patterns.playground/Pages/$1.xcplaygroundpage/Contents.swift +} + +playground() { + combineSwift source/$1 $1.swift + move $1 +} + +combineMarkdown() { + cat $1/header.md > $2 + + { rm $2 && awk '{gsub("\\*/", "", $0); print}' > $2; } < $2 + { rm $2 && awk '{gsub("/\\*:", "", $0); print}' > $2; } < $2 + + cat source/startSwiftCode >> $2 + cat $1/*.swift >> $2 + + { rm $2 && awk '{gsub("\\*//\\*:", "", $0); print}' > $2; } < $2 + { rm $2 && awk '{gsub("\\*/", "\n```swift", $0); print}' > $2; } < $2 + { rm $2 && awk '{gsub("/\\*:", "```\n", $0); print}' > $2; } < $2 + + cat source/endSwiftCode >> $2 + + { rm $2 && awk '{gsub("```swift```", "", $0); print}' > $2; } < $2 + + cat $2 >> README.md + rm $2 +} + +readme() { + combineMarkdown source/$1 $1.md +} + +playground Index +playground Behavioral +playground Creational +playground Structural + +zip -r -X Design-Patterns.playground.zip ./Design-Patterns.playground + +echo "" > README.md + +readme Index +cat source/contentsReadme.md >> README.md +readme Behavioral +readme Creational +readme Structural +cat source/footer.md >> README.md \ No newline at end of file diff --git a/source-cn/Index/header.md b/source-cn/Index/header.md new file mode 100644 index 0000000..9b34f8f --- /dev/null +++ b/source-cn/Index/header.md @@ -0,0 +1,9 @@ + +Design Patterns implemented in Swift 5.0 +======================================== + +A short cheat-sheet with Xcode 10.2 Playground ([Design-Patterns.playground.zip](https://raw.githubusercontent.com/ochococo/Design-Patterns-In-Swift/master/Design-Patterns.playground.zip)). + +👷 Project maintained by: [@nsmeme](http://twitter.com/nsmeme) (Oktawian Chojnacki) + +🚀 How to generate README, Playground and zip from source: [GENERATE.md](https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/GENERATE.md) diff --git a/source-cn/Index/welcome.swift b/source-cn/Index/welcome.swift new file mode 100644 index 0000000..a707971 --- /dev/null +++ b/source-cn/Index/welcome.swift @@ -0,0 +1,2 @@ + +print("Welcome!") diff --git a/source-cn/behavioral/chain_of_responsibility.swift b/source-cn/behavioral/chain_of_responsibility.swift new file mode 100644 index 0000000..cfe527c --- /dev/null +++ b/source-cn/behavioral/chain_of_responsibility.swift @@ -0,0 +1,96 @@ +/*: +🐝 Chain Of Responsibility +-------------------------- + +The chain of responsibility pattern is used to process varied requests, each of which may be dealt with by a different handler. + +### Example: +*/ + +protocol Withdrawing { + func withdraw(amount: Int) -> Bool +} + +final class MoneyPile: Withdrawing { + + let value: Int + var quantity: Int + var next: Withdrawing? + + init(value: Int, quantity: Int, next: Withdrawing?) { + self.value = value + self.quantity = quantity + self.next = next + } + + func withdraw(amount: Int) -> Bool { + + var amount = amount + + func canTakeSomeBill(want: Int) -> Bool { + return (want / self.value) > 0 + } + + var quantity = self.quantity + + while canTakeSomeBill(want: amount) { + + if quantity == 0 { + break + } + + amount -= self.value + quantity -= 1 + } + + guard amount > 0 else { + return true + } + + if let next = self.next { + return next.withdraw(amount: amount) + } + + return false + } +} + +final class ATM: Withdrawing { + + private var hundred: Withdrawing + private var fifty: Withdrawing + private var twenty: Withdrawing + private var ten: Withdrawing + + private var startPile: Withdrawing { + return self.hundred + } + + init(hundred: Withdrawing, + fifty: Withdrawing, + twenty: Withdrawing, + ten: Withdrawing) { + + self.hundred = hundred + self.fifty = fifty + self.twenty = twenty + self.ten = ten + } + + func withdraw(amount: Int) -> Bool { + return startPile.withdraw(amount: amount) + } +} +/*: +### Usage +*/ +// Create piles of money and link them together 10 < 20 < 50 < 100.** +let ten = MoneyPile(value: 10, quantity: 6, next: nil) +let twenty = MoneyPile(value: 20, quantity: 2, next: ten) +let fifty = MoneyPile(value: 50, quantity: 2, next: twenty) +let hundred = MoneyPile(value: 100, quantity: 1, next: fifty) + +// Build ATM. +var atm = ATM(hundred: hundred, fifty: fifty, twenty: twenty, ten: ten) +atm.withdraw(amount: 310) // Cannot because ATM has only 300 +atm.withdraw(amount: 100) // Can withdraw - 1x100 diff --git a/source-cn/behavioral/command.swift b/source-cn/behavioral/command.swift new file mode 100644 index 0000000..c092a3e --- /dev/null +++ b/source-cn/behavioral/command.swift @@ -0,0 +1,61 @@ +/*: +👫 Command +---------- + +The command pattern is used to express a request, including the call to be made and all of its required parameters, in a command object. The command may then be executed immediately or held for later use. + +### Example: +*/ +protocol DoorCommand { + func execute() -> String +} + +final class OpenCommand: DoorCommand { + let doors:String + + required init(doors: String) { + self.doors = doors + } + + func execute() -> String { + return "Opened \(doors)" + } +} + +final class CloseCommand: DoorCommand { + let doors:String + + required init(doors: String) { + self.doors = doors + } + + func execute() -> String { + return "Closed \(doors)" + } +} + +final class HAL9000DoorsOperations { + let openCommand: DoorCommand + let closeCommand: DoorCommand + + init(doors: String) { + self.openCommand = OpenCommand(doors:doors) + self.closeCommand = CloseCommand(doors:doors) + } + + func close() -> String { + return closeCommand.execute() + } + + func open() -> String { + return openCommand.execute() + } +} +/*: +### Usage: +*/ +let podBayDoors = "Pod Bay Doors" +let doorModule = HAL9000DoorsOperations(doors:podBayDoors) + +doorModule.open() +doorModule.close() diff --git a/source-cn/behavioral/header.md b/source-cn/behavioral/header.md new file mode 100644 index 0000000..61e1045 --- /dev/null +++ b/source-cn/behavioral/header.md @@ -0,0 +1,7 @@ + +Behavioral +========== + +>In software engineering, behavioral design patterns are design patterns that identify common communication patterns between objects and realize these patterns. By doing so, these patterns increase flexibility in carrying out this communication. +> +>**Source:** [wikipedia.org](http://en.wikipedia.org/wiki/Behavioral_pattern) diff --git a/source-cn/behavioral/interpreter.swift b/source-cn/behavioral/interpreter.swift new file mode 100644 index 0000000..09427b3 --- /dev/null +++ b/source-cn/behavioral/interpreter.swift @@ -0,0 +1,89 @@ +/*: +🎶 Interpreter +-------------- + +The interpreter pattern is used to evaluate sentences in a language. + +### Example +*/ + +protocol IntegerExpression { + func evaluate(_ context: IntegerContext) -> Int + func replace(character: Character, integerExpression: IntegerExpression) -> IntegerExpression + func copied() -> IntegerExpression +} + +final class IntegerContext { + private var data: [Character:Int] = [:] + + func lookup(name: Character) -> Int { + return self.data[name]! + } + + func assign(expression: IntegerVariableExpression, value: Int) { + self.data[expression.name] = value + } +} + +final class IntegerVariableExpression: IntegerExpression { + let name: Character + + init(name: Character) { + self.name = name + } + + func evaluate(_ context: IntegerContext) -> Int { + return context.lookup(name: self.name) + } + + func replace(character name: Character, integerExpression: IntegerExpression) -> IntegerExpression { + if name == self.name { + return integerExpression.copied() + } else { + return IntegerVariableExpression(name: self.name) + } + } + + func copied() -> IntegerExpression { + return IntegerVariableExpression(name: self.name) + } +} + +final class AddExpression: IntegerExpression { + private var operand1: IntegerExpression + private var operand2: IntegerExpression + + init(op1: IntegerExpression, op2: IntegerExpression) { + self.operand1 = op1 + self.operand2 = op2 + } + + func evaluate(_ context: IntegerContext) -> Int { + return self.operand1.evaluate(context) + self.operand2.evaluate(context) + } + + func replace(character: Character, integerExpression: IntegerExpression) -> IntegerExpression { + return AddExpression(op1: operand1.replace(character: character, integerExpression: integerExpression), + op2: operand2.replace(character: character, integerExpression: integerExpression)) + } + + func copied() -> IntegerExpression { + return AddExpression(op1: self.operand1, op2: self.operand2) + } +} +/*: +### Usage +*/ +var context = IntegerContext() + +var a = IntegerVariableExpression(name: "A") +var b = IntegerVariableExpression(name: "B") +var c = IntegerVariableExpression(name: "C") + +var expression = AddExpression(op1: a, op2: AddExpression(op1: b, op2: c)) // a + (b + c) + +context.assign(expression: a, value: 2) +context.assign(expression: b, value: 1) +context.assign(expression: c, value: 3) + +var result = expression.evaluate(context) diff --git a/source-cn/behavioral/iterator.swift b/source-cn/behavioral/iterator.swift new file mode 100644 index 0000000..d351958 --- /dev/null +++ b/source-cn/behavioral/iterator.swift @@ -0,0 +1,44 @@ +/*: +🍫 Iterator +----------- + +The iterator pattern is used to provide a standard interface for traversing a collection of items in an aggregate object without the need to understand its underlying structure. + +### Example: +*/ +struct Novella { + let name: String +} + +struct Novellas { + let novellas: [Novella] +} + +struct NovellasIterator: IteratorProtocol { + + private var current = 0 + private let novellas: [Novella] + + init(novellas: [Novella]) { + self.novellas = novellas + } + + mutating func next() -> Novella? { + defer { current += 1 } + return novellas.count > current ? novellas[current] : nil + } +} + +extension Novellas: Sequence { + func makeIterator() -> NovellasIterator { + return NovellasIterator(novellas: novellas) + } +} +/*: +### Usage +*/ +let greatNovellas = Novellas(novellas: [Novella(name: "The Mist")] ) + +for novella in greatNovellas { + print("I've read: \(novella)") +} diff --git a/source-cn/behavioral/mediator.swift b/source-cn/behavioral/mediator.swift new file mode 100644 index 0000000..07648f5 --- /dev/null +++ b/source-cn/behavioral/mediator.swift @@ -0,0 +1,64 @@ +/*: +💐 Mediator +----------- + +The mediator pattern is used to reduce coupling between classes that communicate with each other. Instead of classes communicating directly, and thus requiring knowledge of their implementation, the classes send messages via a mediator object. + +### Example +*/ +protocol Receiver { + associatedtype MessageType + func receive(message: MessageType) +} + +protocol Sender { + associatedtype MessageType + associatedtype ReceiverType: Receiver + + var recipients: [ReceiverType] { get } + + func send(message: MessageType) +} + +struct Programmer: Receiver { + let name: String + + init(name: String) { + self.name = name + } + + func receive(message: String) { + print("\(name) received: \(message)") + } +} + +final class MessageMediator: Sender { + internal var recipients: [Programmer] = [] + + func add(recipient: Programmer) { + recipients.append(recipient) + } + + func send(message: String) { + for recipient in recipients { + recipient.receive(message: message) + } + } +} + +/*: +### Usage +*/ +func spamMonster(message: String, worker: MessageMediator) { + worker.send(message: message) +} + +let messagesMediator = MessageMediator() + +let user0 = Programmer(name: "Linus Torvalds") +let user1 = Programmer(name: "Avadis 'Avie' Tevanian") +messagesMediator.add(recipient: user0) +messagesMediator.add(recipient: user1) + +spamMonster(message: "I'd Like to Add you to My Professional Network", worker: messagesMediator) + diff --git a/source-cn/behavioral/memento.swift b/source-cn/behavioral/memento.swift new file mode 100644 index 0000000..13b0474 --- /dev/null +++ b/source-cn/behavioral/memento.swift @@ -0,0 +1,83 @@ +/*: +💾 Memento +---------- + +The memento pattern is used to capture the current state of an object and store it in such a manner that it can be restored at a later time without breaking the rules of encapsulation. + +### Example +*/ +typealias Memento = [String: String] +/*: +Originator +*/ +protocol MementoConvertible { + var memento: Memento { get } + init?(memento: Memento) +} + +struct GameState: MementoConvertible { + + private enum Keys { + static let chapter = "com.valve.halflife.chapter" + static let weapon = "com.valve.halflife.weapon" + } + + var chapter: String + var weapon: String + + init(chapter: String, weapon: String) { + self.chapter = chapter + self.weapon = weapon + } + + init?(memento: Memento) { + guard let mementoChapter = memento[Keys.chapter], + let mementoWeapon = memento[Keys.weapon] else { + return nil + } + + chapter = mementoChapter + weapon = mementoWeapon + } + + var memento: Memento { + return [ Keys.chapter: chapter, Keys.weapon: weapon ] + } +} +/*: +Caretaker +*/ +enum CheckPoint { + + private static let defaults = UserDefaults.standard + + static func save(_ state: MementoConvertible, saveName: String) { + defaults.set(state.memento, forKey: saveName) + defaults.synchronize() + } + + static func restore(saveName: String) -> Any? { + return defaults.object(forKey: saveName) + } +} +/*: +### Usage +*/ +var gameState = GameState(chapter: "Black Mesa Inbound", weapon: "Crowbar") + +gameState.chapter = "Anomalous Materials" +gameState.weapon = "Glock 17" +CheckPoint.save(gameState, saveName: "gameState1") + +gameState.chapter = "Unforeseen Consequences" +gameState.weapon = "MP5" +CheckPoint.save(gameState, saveName: "gameState2") + +gameState.chapter = "Office Complex" +gameState.weapon = "Crossbow" +CheckPoint.save(gameState, saveName: "gameState3") + +if let memento = CheckPoint.restore(saveName: "gameState1") as? Memento { + let finalState = GameState(memento: memento) + dump(finalState) +} diff --git a/source-cn/behavioral/observer.swift b/source-cn/behavioral/observer.swift new file mode 100644 index 0000000..aec0ac8 --- /dev/null +++ b/source-cn/behavioral/observer.swift @@ -0,0 +1,50 @@ +/*: +👓 Observer +----------- + +The observer pattern is used to allow an object to publish changes to its state. +Other objects subscribe to be immediately notified of any changes. + +### Example +*/ +protocol PropertyObserver : class { + func willChange(propertyName: String, newPropertyValue: Any?) + func didChange(propertyName: String, oldPropertyValue: Any?) +} + +final class TestChambers { + + weak var observer:PropertyObserver? + + private let testChamberNumberName = "testChamberNumber" + + var testChamberNumber: Int = 0 { + willSet(newValue) { + observer?.willChange(propertyName: testChamberNumberName, newPropertyValue: newValue) + } + didSet { + observer?.didChange(propertyName: testChamberNumberName, oldPropertyValue: oldValue) + } + } +} + +final class Observer : PropertyObserver { + func willChange(propertyName: String, newPropertyValue: Any?) { + if newPropertyValue as? Int == 1 { + print("Okay. Look. We both said a lot of things that you're going to regret.") + } + } + + func didChange(propertyName: String, oldPropertyValue: Any?) { + if oldPropertyValue as? Int == 0 { + print("Sorry about the mess. I've really let the place go since you killed me.") + } + } +} +/*: +### Usage +*/ +var observerInstance = Observer() +var testChambers = TestChambers() +testChambers.observer = observerInstance +testChambers.testChamberNumber += 1 diff --git a/source-cn/behavioral/state.swift b/source-cn/behavioral/state.swift new file mode 100644 index 0000000..14d84c1 --- /dev/null +++ b/source-cn/behavioral/state.swift @@ -0,0 +1,58 @@ +/*: +🐉 State +--------- + +The state pattern is used to alter the behaviour of an object as its internal state changes. +The pattern allows the class for an object to apparently change at run-time. + +### Example +*/ +final class Context { + private var state: State = UnauthorizedState() + + var isAuthorized: Bool { + get { return state.isAuthorized(context: self) } + } + + var userId: String? { + get { return state.userId(context: self) } + } + + func changeStateToAuthorized(userId: String) { + state = AuthorizedState(userId: userId) + } + + func changeStateToUnauthorized() { + state = UnauthorizedState() + } +} + +protocol State { + func isAuthorized(context: Context) -> Bool + func userId(context: Context) -> String? +} + +class UnauthorizedState: State { + func isAuthorized(context: Context) -> Bool { return false } + + func userId(context: Context) -> String? { return nil } +} + +class AuthorizedState: State { + let userId: String + + init(userId: String) { self.userId = userId } + + func isAuthorized(context: Context) -> Bool { return true } + + func userId(context: Context) -> String? { return userId } +} +/*: +### Usage +*/ +let userContext = Context() +(userContext.isAuthorized, userContext.userId) +userContext.changeStateToAuthorized(userId: "admin") +(userContext.isAuthorized, userContext.userId) // now logged in as "admin" +userContext.changeStateToUnauthorized() +(userContext.isAuthorized, userContext.userId) diff --git a/source-cn/behavioral/strategy.swift b/source-cn/behavioral/strategy.swift new file mode 100644 index 0000000..f358961 --- /dev/null +++ b/source-cn/behavioral/strategy.swift @@ -0,0 +1,58 @@ +/*: +💡 Strategy +----------- + +The strategy pattern is used to create an interchangeable family of algorithms from which the required process is chosen at run-time. + +### Example +*/ + +struct TestSubject { + let pupilDiameter: Double + let blushResponse: Double + let isOrganic: Bool +} + +protocol RealnessTesting: AnyObject { + func testRealness(_ testSubject: TestSubject) -> Bool +} + +final class VoightKampffTest: RealnessTesting { + func testRealness(_ testSubject: TestSubject) -> Bool { + return testSubject.pupilDiameter < 30.0 || testSubject.blushResponse == 0.0 + } +} + +final class GeneticTest: RealnessTesting { + func testRealness(_ testSubject: TestSubject) -> Bool { + return testSubject.isOrganic + } +} + +final class BladeRunner { + private let strategy: RealnessTesting + + init(test: RealnessTesting) { + self.strategy = test + } + + func testIfAndroid(_ testSubject: TestSubject) -> Bool { + return !strategy.testRealness(testSubject) + } +} + +/*: + ### Usage + */ + +let rachel = TestSubject(pupilDiameter: 30.2, + blushResponse: 0.3, + isOrganic: false) + +// Deckard is using a traditional test +let deckard = BladeRunner(test: VoightKampffTest()) +let isRachelAndroid = deckard.testIfAndroid(rachel) + +// Gaff is using a very precise method +let gaff = BladeRunner(test: GeneticTest()) +let isDeckardAndroid = gaff.testIfAndroid(rachel) diff --git a/source-cn/behavioral/visitor.swift b/source-cn/behavioral/visitor.swift new file mode 100644 index 0000000..d53e409 --- /dev/null +++ b/source-cn/behavioral/visitor.swift @@ -0,0 +1,57 @@ +/*: +🏃 Visitor +---------- + +The visitor pattern is used to separate a relatively complex set of structured data classes from the functionality that may be performed upon the data that they hold. + +### Example +*/ +protocol PlanetVisitor { + func visit(planet: PlanetAlderaan) + func visit(planet: PlanetCoruscant) + func visit(planet: PlanetTatooine) + func visit(planet: MoonJedha) +} + +protocol Planet { + func accept(visitor: PlanetVisitor) +} + +final class MoonJedha: Planet { + func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) } +} + +final class PlanetAlderaan: Planet { + func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) } +} + +final class PlanetCoruscant: Planet { + func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) } +} + +final class PlanetTatooine: Planet { + func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) } +} + +final class NameVisitor: PlanetVisitor { + var name = "" + + func visit(planet: PlanetAlderaan) { name = "Alderaan" } + func visit(planet: PlanetCoruscant) { name = "Coruscant" } + func visit(planet: PlanetTatooine) { name = "Tatooine" } + func visit(planet: MoonJedha) { name = "Jedha" } +} + +/*: +### Usage +*/ +let planets: [Planet] = [PlanetAlderaan(), PlanetCoruscant(), PlanetTatooine(), MoonJedha()] + +let names = planets.map { (planet: Planet) -> String in + let visitor = NameVisitor() + planet.accept(visitor: visitor) + + return visitor.name +} + +names diff --git a/source-cn/contents.md b/source-cn/contents.md new file mode 100644 index 0000000..8503238 --- /dev/null +++ b/source-cn/contents.md @@ -0,0 +1,6 @@ + +## Table of Contents + +* [Behavioral](Behavioral) +* [Creational](Creational) +* [Structural](Structural) diff --git a/source-cn/contentsReadme.md b/source-cn/contentsReadme.md new file mode 100644 index 0000000..7a92ac8 --- /dev/null +++ b/source-cn/contentsReadme.md @@ -0,0 +1,16 @@ + +## Table of Contents + +| [Behavioral](#behavioral) | [Creational](#creational) | [Structural](#structural) | +| ------------------------------------------------------ | ---------------------------------------- | ---------------------------------------- | +| [🐝 Chain Of Responsibility](#-chain-of-responsibility) | [🌰 Abstract Factory](#-abstract-factory) | [🔌 Adapter](#-adapter) | +| [👫 Command](#-command) | [👷 Builder](#-builder) | [🌉 Bridge](#-bridge) | +| [🎶 Interpreter](#-interpreter) | [🏭 Factory Method](#-factory-method) | [🌿 Composite](#-composite) | +| [🍫 Iterator](#-iterator) | [🃏 Prototype](#-prototype) | [🍧 Decorator](#-decorator) | +| [💐 Mediator](#-mediator) | [💍 Singleton](#-singleton) | [🎁 Façade](#-fa-ade) | +| [💾 Memento](#-memento) | | [🍃 Flyweight](#-flyweight) | +| [👓 Observer](#-observer) | | [☔ Protection Proxy](#-protection-proxy) | +| [🐉 State](#-state) | | [🍬 Virtual Proxy](#-virtual-proxy) | +| [💡 Strategy](#-strategy) | | | +| [🏃 Visitor](#-visitor) | | | + diff --git a/source-cn/creational/abstract_factory.swift b/source-cn/creational/abstract_factory.swift new file mode 100644 index 0000000..16d2899 --- /dev/null +++ b/source-cn/creational/abstract_factory.swift @@ -0,0 +1,61 @@ +/*: +🌰 Abstract Factory +------------------- + +The abstract factory pattern is used to provide a client with a set of related or dependant objects. +The "family" of objects created by the factory are determined at run-time. + +### Example + +Protocols +*/ + +protocol BurgerDescribing { + var ingredients: [String] { get } +} + +struct CheeseBurger: BurgerDescribing { + let ingredients: [String] +} + +protocol BurgerMaking { + func make() -> BurgerDescribing +} + +// Number implementations with factory methods + +final class BigKahunaBurger: BurgerMaking { + func make() -> BurgerDescribing { + return CheeseBurger(ingredients: ["Cheese", "Burger", "Lettuce", "Tomato"]) + } +} + +final class JackInTheBox: BurgerMaking { + func make() -> BurgerDescribing { + return CheeseBurger(ingredients: ["Cheese", "Burger", "Tomato", "Onions"]) + } +} + +/*: +Abstract factory +*/ + +enum BurgerFactoryType: BurgerMaking { + + case bigKahuna + case jackInTheBox + + func make() -> BurgerDescribing { + switch self { + case .bigKahuna: + return BigKahunaBurger().make() + case .jackInTheBox: + return JackInTheBox().make() + } + } +} +/*: +### Usage +*/ +let bigKahuna = BurgerFactoryType.bigKahuna.make() +let jackInTheBox = BurgerFactoryType.jackInTheBox.make() diff --git a/source-cn/creational/builder.swift b/source-cn/creational/builder.swift new file mode 100644 index 0000000..139139a --- /dev/null +++ b/source-cn/creational/builder.swift @@ -0,0 +1,53 @@ +/*: +👷 Builder +---------- + +The builder pattern is used to create complex objects with constituent parts that must be created in the same order or using a specific algorithm. +An external class controls the construction algorithm. + +### Example +*/ +final class DeathStarBuilder { + + var x: Double? + var y: Double? + var z: Double? + + typealias BuilderClosure = (DeathStarBuilder) -> () + + init(buildClosure: BuilderClosure) { + buildClosure(self) + } +} + +struct DeathStar : CustomStringConvertible { + + let x: Double + let y: Double + let z: Double + + init?(builder: DeathStarBuilder) { + + if let x = builder.x, let y = builder.y, let z = builder.z { + self.x = x + self.y = y + self.z = z + } else { + return nil + } + } + + var description:String { + return "Death Star at (x:\(x) y:\(y) z:\(z))" + } +} +/*: +### Usage +*/ +let empire = DeathStarBuilder { builder in + builder.x = 0.1 + builder.y = 0.2 + builder.z = 0.3 +} + +let deathStar = DeathStar(builder:empire) diff --git a/source-cn/creational/factory.swift b/source-cn/creational/factory.swift new file mode 100644 index 0000000..aeee853 --- /dev/null +++ b/source-cn/creational/factory.swift @@ -0,0 +1,63 @@ +/*: +🏭 Factory Method +----------------- + +The factory pattern is used to replace class constructors, abstracting the process of object generation so that the type of the object instantiated can be determined at run-time. + +### Example +*/ +protocol CurrencyDescribing { + var symbol: String { get } + var code: String { get } +} + +final class Euro: CurrencyDescribing { + var symbol: String { + return "€" + } + + var code: String { + return "EUR" + } +} + +final class UnitedStatesDolar: CurrencyDescribing { + var symbol: String { + return "$" + } + + var code: String { + return "USD" + } +} + +enum Country { + case unitedStates + case spain + case uk + case greece +} + +enum CurrencyFactory { + static func currency(for country: Country) -> CurrencyDescribing? { + + switch country { + case .spain, .greece: + return Euro() + case .unitedStates: + return UnitedStatesDolar() + default: + return nil + } + + } +} +/*: +### Usage +*/ +let noCurrencyCode = "No Currency Code Available" + +CurrencyFactory.currency(for: .greece)?.code ?? noCurrencyCode +CurrencyFactory.currency(for: .spain)?.code ?? noCurrencyCode +CurrencyFactory.currency(for: .unitedStates)?.code ?? noCurrencyCode +CurrencyFactory.currency(for: .uk)?.code ?? noCurrencyCode diff --git a/source-cn/creational/header.md b/source-cn/creational/header.md new file mode 100644 index 0000000..1684668 --- /dev/null +++ b/source-cn/creational/header.md @@ -0,0 +1,7 @@ + +Creational +========== + +> In software engineering, creational design patterns are design patterns that deal with object creation mechanisms, trying to create objects in a manner suitable to the situation. The basic form of object creation could result in design problems or added complexity to the design. Creational design patterns solve this problem by somehow controlling this object creation. +> +>**Source:** [wikipedia.org](http://en.wikipedia.org/wiki/Creational_pattern) diff --git a/source-cn/creational/prototype.swift b/source-cn/creational/prototype.swift new file mode 100644 index 0000000..7840489 --- /dev/null +++ b/source-cn/creational/prototype.swift @@ -0,0 +1,35 @@ +/*: +🃏 Prototype +------------ + +The prototype pattern is used to instantiate a new object by copying all of the properties of an existing object, creating an independent clone. +This practise is particularly useful when the construction of a new object is inefficient. + +### Example +*/ +struct MoonWorker { + + let name: String + var health: Int = 100 + + init(name: String) { + self.name = name + } + + func clone() -> MoonWorker { + return MoonWorker(name: name) + } +} +/*: +### Usage +*/ +let prototype = MoonWorker(name: "Sam Bell") + +var bell1 = prototype.clone() +bell1.health = 12 + +var bell2 = prototype.clone() +bell2.health = 23 + +var bell3 = prototype.clone() +bell3.health = 0 diff --git a/source-cn/creational/singleton.swift b/source-cn/creational/singleton.swift new file mode 100644 index 0000000..539bca5 --- /dev/null +++ b/source-cn/creational/singleton.swift @@ -0,0 +1,22 @@ +/*: +💍 Singleton +------------ + +The singleton pattern ensures that only one object of a particular class is ever created. +All further references to objects of the singleton class refer to the same underlying instance. +There are very few applications, do not overuse this pattern! + +### Example: +*/ +final class ElonMusk { + + static let shared = ElonMusk() + + private init() { + // Private initialization to ensure just one instance is created. + } +} +/*: +### Usage: +*/ +let elon = ElonMusk.shared // There is only one Elon Musk folks. diff --git a/source-cn/endComment b/source-cn/endComment new file mode 100644 index 0000000..9f82b4e --- /dev/null +++ b/source-cn/endComment @@ -0,0 +1,2 @@ + +*/ \ No newline at end of file diff --git a/source-cn/endSwiftCode b/source-cn/endSwiftCode new file mode 100644 index 0000000..7dc72a8 --- /dev/null +++ b/source-cn/endSwiftCode @@ -0,0 +1,2 @@ +``` + diff --git a/source-cn/footer.md b/source-cn/footer.md new file mode 100644 index 0000000..21002da --- /dev/null +++ b/source-cn/footer.md @@ -0,0 +1,5 @@ + +Info +==== + +📖 Descriptions from: [Gang of Four Design Patterns Reference Sheet](http://www.blackwasp.co.uk/GangOfFour.aspx) diff --git a/source-cn/imports.swift b/source-cn/imports.swift new file mode 100644 index 0000000..350c82f --- /dev/null +++ b/source-cn/imports.swift @@ -0,0 +1,2 @@ + +import Foundation diff --git a/source-cn/startComment b/source-cn/startComment new file mode 100644 index 0000000..a23f02a --- /dev/null +++ b/source-cn/startComment @@ -0,0 +1 @@ +/*: diff --git a/source-cn/startSwiftCode b/source-cn/startSwiftCode new file mode 100644 index 0000000..591b2be --- /dev/null +++ b/source-cn/startSwiftCode @@ -0,0 +1,3 @@ + + +```swift \ No newline at end of file diff --git a/source-cn/structural/adapter.swift b/source-cn/structural/adapter.swift new file mode 100644 index 0000000..3a99081 --- /dev/null +++ b/source-cn/structural/adapter.swift @@ -0,0 +1,51 @@ +/*: +🔌 Adapter +---------- + +The adapter pattern is used to provide a link between two otherwise incompatible types by wrapping the "adaptee" with a class that supports the interface required by the client. + +### Example +*/ +protocol NewDeathStarSuperLaserAiming { + var angleV: Double { get } + var angleH: Double { get } +} +/*: +**Adaptee** +*/ +struct OldDeathStarSuperlaserTarget { + let angleHorizontal: Float + let angleVertical: Float + + init(angleHorizontal: Float, angleVertical: Float) { + self.angleHorizontal = angleHorizontal + self.angleVertical = angleVertical + } +} +/*: +**Adapter** +*/ +struct NewDeathStarSuperlaserTarget: NewDeathStarSuperLaserAiming { + + private let target: OldDeathStarSuperlaserTarget + + var angleV: Double { + return Double(target.angleVertical) + } + + var angleH: Double { + return Double(target.angleHorizontal) + } + + init(_ target: OldDeathStarSuperlaserTarget) { + self.target = target + } +} +/*: +### Usage +*/ +let target = OldDeathStarSuperlaserTarget(angleHorizontal: 14.0, angleVertical: 12.0) +let newFormat = NewDeathStarSuperlaserTarget(target) + +newFormat.angleH +newFormat.angleV diff --git a/source-cn/structural/bridge.swift b/source-cn/structural/bridge.swift new file mode 100644 index 0000000..2384c7e --- /dev/null +++ b/source-cn/structural/bridge.swift @@ -0,0 +1,48 @@ +/*: +🌉 Bridge +---------- + +The bridge pattern is used to separate the abstract elements of a class from the implementation details, providing the means to replace the implementation details without modifying the abstraction. + +### Example +*/ +protocol Switch { + var appliance: Appliance { get set } + func turnOn() +} + +protocol Appliance { + func run() +} + +final class RemoteControl: Switch { + var appliance: Appliance + + func turnOn() { + self.appliance.run() + } + + init(appliance: Appliance) { + self.appliance = appliance + } +} + +final class TV: Appliance { + func run() { + print("tv turned on"); + } +} + +final class VacuumCleaner: Appliance { + func run() { + print("vacuum cleaner turned on") + } +} +/*: +### Usage +*/ +let tvRemoteControl = RemoteControl(appliance: TV()) +tvRemoteControl.turnOn() + +let fancyVacuumCleanerRemoteControl = RemoteControl(appliance: VacuumCleaner()) +fancyVacuumCleanerRemoteControl.turnOn() diff --git a/source-cn/structural/composite.swift b/source-cn/structural/composite.swift new file mode 100644 index 0000000..522cd7c --- /dev/null +++ b/source-cn/structural/composite.swift @@ -0,0 +1,50 @@ +/*: +🌿 Composite +------------- + +The composite pattern is used to create hierarchical, recursive tree structures of related objects where any element of the structure may be accessed and utilised in a standard manner. + +### Example + +Component +*/ +protocol Shape { + func draw(fillColor: String) +} +/*: +Leafs +*/ +final class Square: Shape { + func draw(fillColor: String) { + print("Drawing a Square with color \(fillColor)") + } +} + +final class Circle: Shape { + func draw(fillColor: String) { + print("Drawing a circle with color \(fillColor)") + } +} + +/*: +Composite +*/ +final class Whiteboard: Shape { + + private lazy var shapes = [Shape]() + + init(_ shapes: Shape...) { + self.shapes = shapes + } + + func draw(fillColor: String) { + for shape in self.shapes { + shape.draw(fillColor: fillColor) + } + } +} +/*: +### Usage: +*/ +var whiteboard = Whiteboard(Circle(), Square()) +whiteboard.draw(fillColor: "Red") diff --git a/source-cn/structural/decorator.swift b/source-cn/structural/decorator.swift new file mode 100644 index 0000000..c531d1e --- /dev/null +++ b/source-cn/structural/decorator.swift @@ -0,0 +1,62 @@ +/*: +🍧 Decorator +------------ + +The decorator pattern is used to extend or alter the functionality of objects at run- time by wrapping them in an object of a decorator class. +This provides a flexible alternative to using inheritance to modify behaviour. + +### Example +*/ +protocol CostHaving { + var cost: Double { get } +} + +protocol IngredientsHaving { + var ingredients: [String] { get } +} + +typealias BeverageDataHaving = CostHaving & IngredientsHaving + +struct SimpleCoffee: BeverageDataHaving { + let cost: Double = 1.0 + let ingredients = ["Water", "Coffee"] +} + +protocol BeverageHaving: BeverageDataHaving { + var beverage: BeverageDataHaving { get } +} + +struct Milk: BeverageHaving { + + let beverage: BeverageDataHaving + + var cost: Double { + return beverage.cost + 0.5 + } + + var ingredients: [String] { + return beverage.ingredients + ["Milk"] + } +} + +struct WhipCoffee: BeverageHaving { + + let beverage: BeverageDataHaving + + var cost: Double { + return beverage.cost + 0.5 + } + + var ingredients: [String] { + return beverage.ingredients + ["Whip"] + } +} +/*: +### Usage: +*/ +var someCoffee: BeverageDataHaving = SimpleCoffee() +print("Cost: \(someCoffee.cost); Ingredients: \(someCoffee.ingredients)") +someCoffee = Milk(beverage: someCoffee) +print("Cost: \(someCoffee.cost); Ingredients: \(someCoffee.ingredients)") +someCoffee = WhipCoffee(beverage: someCoffee) +print("Cost: \(someCoffee.cost); Ingredients: \(someCoffee.ingredients)") diff --git a/source-cn/structural/facade.swift b/source-cn/structural/facade.swift new file mode 100644 index 0000000..1147d57 --- /dev/null +++ b/source-cn/structural/facade.swift @@ -0,0 +1,36 @@ +/*: +🎁 Façade +--------- + +The facade pattern is used to define a simplified interface to a more complex subsystem. + +### Example +*/ +final class Defaults { + + private let defaults: UserDefaults + + init(defaults: UserDefaults = .standard) { + self.defaults = defaults + } + + subscript(key: String) -> String? { + get { + return defaults.string(forKey: key) + } + + set { + defaults.set(newValue, forKey: key) + } + } +} +/*: +### Usage +*/ +let storage = Defaults() + +// Store +storage["Bishop"] = "Disconnect me. I’d rather be nothing" + +// Read +storage["Bishop"] diff --git a/source-cn/structural/flyweight.swift b/source-cn/structural/flyweight.swift new file mode 100644 index 0000000..3a2d944 --- /dev/null +++ b/source-cn/structural/flyweight.swift @@ -0,0 +1,55 @@ +/*: +## 🍃 Flyweight +The flyweight pattern is used to minimize memory usage or computational expenses by sharing as much as possible with other similar objects. +### Example +*/ +// Instances of SpecialityCoffee will be the Flyweights +struct SpecialityCoffee { + let origin: String +} + +protocol CoffeeSearching { + func search(origin: String) -> SpecialityCoffee? +} + +// Menu acts as a factory and cache for SpecialityCoffee flyweight objects +final class Menu: CoffeeSearching { + + private var coffeeAvailable: [String: SpecialityCoffee] = [:] + + func search(origin: String) -> SpecialityCoffee? { + if coffeeAvailable.index(forKey: origin) == nil { + coffeeAvailable[origin] = SpecialityCoffee(origin: origin) + } + + return coffeeAvailable[origin] + } +} + +final class CoffeeShop { + private var orders: [Int: SpecialityCoffee] = [:] + private let menu: CoffeeSearching + + init(menu: CoffeeSearching) { + self.menu = menu + } + + func takeOrder(origin: String, table: Int) { + orders[table] = menu.search(origin: origin) + } + + func serve() { + for (table, origin) in orders { + print("Serving \(origin) to table \(table)") + } + } +} +/*: +### Usage +*/ +let coffeeShop = CoffeeShop(menu: Menu()) + +coffeeShop.takeOrder(origin: "Yirgacheffe, Ethiopia", table: 1) +coffeeShop.takeOrder(origin: "Buziraguhindwa, Burundi", table: 3) + +coffeeShop.serve() diff --git a/source-cn/structural/header.md b/source-cn/structural/header.md new file mode 100644 index 0000000..67cdc66 --- /dev/null +++ b/source-cn/structural/header.md @@ -0,0 +1,7 @@ + +Structural +========== + +>In software engineering, structural design patterns are design patterns that ease the design by identifying a simple way to realize relationships between entities. +> +>**Source:** [wikipedia.org](http://en.wikipedia.org/wiki/Structural_pattern) diff --git a/source-cn/structural/protection_proxy.swift b/source-cn/structural/protection_proxy.swift new file mode 100644 index 0000000..f012f47 --- /dev/null +++ b/source-cn/structural/protection_proxy.swift @@ -0,0 +1,52 @@ +/*: +☔ Protection Proxy +------------------ + +The proxy pattern is used to provide a surrogate or placeholder object, which references an underlying object. +Protection proxy is restricting access. + +### Example +*/ +protocol DoorOpening { + func open(doors: String) -> String +} + +final class HAL9000: DoorOpening { + func open(doors: String) -> String { + return ("HAL9000: Affirmative, Dave. I read you. Opened \(doors).") + } +} + +final class CurrentComputer: DoorOpening { + private var computer: HAL9000! + + func authenticate(password: String) -> Bool { + + guard password == "pass" else { + return false + } + + computer = HAL9000() + + return true + } + + func open(doors: String) -> String { + + guard computer != nil else { + return "Access Denied. I'm afraid I can't do that." + } + + return computer.open(doors: doors) + } +} +/*: +### Usage +*/ +let computer = CurrentComputer() +let podBay = "Pod Bay Doors" + +computer.open(doors: podBay) + +computer.authenticate(password: "pass") +computer.open(doors: podBay) diff --git a/source-cn/structural/virtual_proxy.swift b/source-cn/structural/virtual_proxy.swift new file mode 100644 index 0000000..9a02414 --- /dev/null +++ b/source-cn/structural/virtual_proxy.swift @@ -0,0 +1,32 @@ +/*: +🍬 Virtual Proxy +---------------- + +The proxy pattern is used to provide a surrogate or placeholder object, which references an underlying object. +Virtual proxy is used for loading object on demand. + +### Example +*/ +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() + } +} +/*: +### Usage +*/ +let humanInterface = HEVSuitHumanInterface() +humanInterface.administerMorphine() From e9b2e4c64384ff36d2f0fec04263f7878e151386 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=85=B4=E5=BD=AC=5FBinboy?= Date: Fri, 13 Mar 2020 23:05:04 +0800 Subject: [PATCH 25/66] Translate to chinese --- generate-playground-cn.sh | 26 +++++++++---------- source-cn/Index/header.md | 8 +++--- .../behavioral/chain_of_responsibility.swift | 16 ++++++------ source-cn/behavioral/command.swift | 15 ++++++----- source-cn/behavioral/header.md | 12 ++++----- source-cn/behavioral/interpreter.swift | 10 +++---- source-cn/behavioral/iterator.swift | 12 ++++----- source-cn/behavioral/mediator.swift | 10 +++---- source-cn/behavioral/memento.swift | 14 +++++----- source-cn/behavioral/observer.swift | 11 ++++---- source-cn/behavioral/state.swift | 10 +++---- source-cn/behavioral/strategy.swift | 13 ++++++---- source-cn/behavioral/visitor.swift | 10 +++---- source-cn/contents.md | 8 +++--- source-cn/creational/abstract_factory.swift | 17 ++++++------ source-cn/creational/builder.swift | 11 ++++---- source-cn/creational/factory.swift | 10 +++---- source-cn/creational/header.md | 13 +++++----- source-cn/creational/prototype.swift | 11 ++++---- source-cn/creational/singleton.swift | 12 ++++----- source-cn/structural/adapter.swift | 14 +++++----- source-cn/structural/bridge.swift | 10 +++---- source-cn/structural/composite.swift | 16 ++++++------ source-cn/structural/decorator.swift | 12 ++++----- source-cn/structural/facade.swift | 10 +++---- source-cn/structural/flyweight.swift | 4 +-- source-cn/structural/header.md | 8 +++--- source-cn/structural/protection_proxy.swift | 10 +++---- source-cn/structural/virtual_proxy.swift | 10 +++---- 29 files changed, 170 insertions(+), 173 deletions(-) diff --git a/generate-playground-cn.sh b/generate-playground-cn.sh index 9e87220..2bb3c19 100755 --- a/generate-playground-cn.sh +++ b/generate-playground-cn.sh @@ -3,22 +3,22 @@ # Note: I think this part is absolute garbage but it's a snapshot of my current skills with Bash. # Would love to rewrite it in Swift soon. -combineSwift() { - cat source/startComment > $2 +combineSwiftCN() { + cat source-cn/startComment > $2 cat $1/header.md >> $2 - cat source/contents.md >> $2 - cat source/endComment >> $2 - cat source/imports.swift >> $2 + cat source-cn/contents.md >> $2 + cat source-cn/endComment >> $2 + cat source-cn/imports.swift >> $2 cat $1/*.swift >> $2 { rm $2 && awk '{gsub("\\*//\\*:", "", $0); print}' > $2; } < $2 } move() { - mv $1.swift Design-Patterns.playground/Pages/$1.xcplaygroundpage/Contents.swift + mv $1.swift Design-Patterns-CN.playground/Pages/$1.xcplaygroundpage/Contents.swift } playground() { - combineSwift source/$1 $1.swift + combineSwift source-cn/$1 $1.swift move $1 } @@ -28,14 +28,14 @@ combineMarkdown() { { rm $2 && awk '{gsub("\\*/", "", $0); print}' > $2; } < $2 { rm $2 && awk '{gsub("/\\*:", "", $0); print}' > $2; } < $2 - cat source/startSwiftCode >> $2 + cat source-cn/startSwiftCode >> $2 cat $1/*.swift >> $2 { rm $2 && awk '{gsub("\\*//\\*:", "", $0); print}' > $2; } < $2 { rm $2 && awk '{gsub("\\*/", "\n```swift", $0); print}' > $2; } < $2 { rm $2 && awk '{gsub("/\\*:", "```\n", $0); print}' > $2; } < $2 - cat source/endSwiftCode >> $2 + cat source-cn/endSwiftCode >> $2 { rm $2 && awk '{gsub("```swift```", "", $0); print}' > $2; } < $2 @@ -44,7 +44,7 @@ combineMarkdown() { } readme() { - combineMarkdown source/$1 $1.md + combineMarkdown source-cn/$1 $1.md } playground Index @@ -52,13 +52,13 @@ playground Behavioral playground Creational playground Structural -zip -r -X Design-Patterns.playground.zip ./Design-Patterns.playground +zip -r -X Design-Patterns-CN.playground.zip ./Design-Patterns-CN.playground echo "" > README.md readme Index -cat source/contentsReadme.md >> README.md +cat source-cn/contentsReadme.md >> README.md readme Behavioral readme Creational readme Structural -cat source/footer.md >> README.md \ No newline at end of file +cat source-cn/footer.md >> README.md \ No newline at end of file diff --git a/source-cn/Index/header.md b/source-cn/Index/header.md index 9b34f8f..18f7f0c 100644 --- a/source-cn/Index/header.md +++ b/source-cn/Index/header.md @@ -1,9 +1,7 @@ -Design Patterns implemented in Swift 5.0 +设计模式(Swift 5.0 实现) ======================================== -A short cheat-sheet with Xcode 10.2 Playground ([Design-Patterns.playground.zip](https://raw.githubusercontent.com/ochococo/Design-Patterns-In-Swift/master/Design-Patterns.playground.zip)). +👷 源项目由 [@nsmeme](http://twitter.com/nsmeme) (Oktawian Chojnacki) 维护。 -👷 Project maintained by: [@nsmeme](http://twitter.com/nsmeme) (Oktawian Chojnacki) - -🚀 How to generate README, Playground and zip from source: [GENERATE.md](https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/GENERATE.md) +🇨🇳 中文版由 [@binglogo](https://twitter.com/binglogo) 整理翻译。 diff --git a/source-cn/behavioral/chain_of_responsibility.swift b/source-cn/behavioral/chain_of_responsibility.swift index cfe527c..dbba65c 100644 --- a/source-cn/behavioral/chain_of_responsibility.swift +++ b/source-cn/behavioral/chain_of_responsibility.swift @@ -1,10 +1,10 @@ /*: -🐝 Chain Of Responsibility --------------------------- +🐝 责任链(Chain Of Responsibility) +------------------------------ -The chain of responsibility pattern is used to process varied requests, each of which may be dealt with by a different handler. +责任链模式在面向对象程式设计里是一种软件设计模式,它包含了一些命令对象和一系列的处理对象。每一个处理对象决定它能处理哪些命令对象,它也知道如何将它不能处理的命令对象传递给该链中的下一个处理对象。 -### Example: +### 示例: */ protocol Withdrawing { @@ -82,15 +82,15 @@ final class ATM: Withdrawing { } } /*: -### Usage -*/ -// Create piles of money and link them together 10 < 20 < 50 < 100.** + ### 用法 + */ +// 创建一系列的钱堆,并将其链接起来:10<20<50<100 let ten = MoneyPile(value: 10, quantity: 6, next: nil) let twenty = MoneyPile(value: 20, quantity: 2, next: ten) let fifty = MoneyPile(value: 50, quantity: 2, next: twenty) let hundred = MoneyPile(value: 100, quantity: 1, next: fifty) -// Build ATM. +// 创建 ATM 实例 var atm = ATM(hundred: hundred, fifty: fifty, twenty: twenty, ten: ten) atm.withdraw(amount: 310) // Cannot because ATM has only 300 atm.withdraw(amount: 100) // Can withdraw - 1x100 diff --git a/source-cn/behavioral/command.swift b/source-cn/behavioral/command.swift index c092a3e..a04e7ad 100644 --- a/source-cn/behavioral/command.swift +++ b/source-cn/behavioral/command.swift @@ -1,10 +1,11 @@ /*: -👫 Command ----------- - -The command pattern is used to express a request, including the call to be made and all of its required parameters, in a command object. The command may then be executed immediately or held for later use. - -### Example: +👫 命令(Command) + ------------ + 命令模式是一种设计模式,它尝试以对象来代表实际行动。命令对象可以把行动(action) 及其参数封装起来,于是这些行动可以被: + * 重复多次 + * 取消(如果该对象有实现的话) + * 取消后又再重做 + ### 示例: */ protocol DoorCommand { func execute() -> String @@ -52,7 +53,7 @@ final class HAL9000DoorsOperations { } } /*: -### Usage: +### 用法 */ let podBayDoors = "Pod Bay Doors" let doorModule = HAL9000DoorsOperations(doors:podBayDoors) diff --git a/source-cn/behavioral/header.md b/source-cn/behavioral/header.md index 61e1045..376496b 100644 --- a/source-cn/behavioral/header.md +++ b/source-cn/behavioral/header.md @@ -1,7 +1,7 @@ -Behavioral -========== - ->In software engineering, behavioral design patterns are design patterns that identify common communication patterns between objects and realize these patterns. By doing so, these patterns increase flexibility in carrying out this communication. -> ->**Source:** [wikipedia.org](http://en.wikipedia.org/wiki/Behavioral_pattern) + 行为型模式 + ======== + + >在软件工程中, 行为型模式为设计模式的一种类型,用来识别对象之间的常用交流模式并加以实现。如此,可在进行这些交流活动时增强弹性。 + > + >**来源:** [维基百科](https://zh.wikipedia.org/wiki/%E8%A1%8C%E7%82%BA%E5%9E%8B%E6%A8%A1%E5%BC%8F) diff --git a/source-cn/behavioral/interpreter.swift b/source-cn/behavioral/interpreter.swift index 09427b3..4cc8013 100644 --- a/source-cn/behavioral/interpreter.swift +++ b/source-cn/behavioral/interpreter.swift @@ -1,10 +1,10 @@ /*: -🎶 Interpreter --------------- +🎶 解释器(Interpreter) + ------------------ -The interpreter pattern is used to evaluate sentences in a language. + 给定一种语言,定义他的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中句子。 -### Example + ### 示例: */ protocol IntegerExpression { @@ -72,7 +72,7 @@ final class AddExpression: IntegerExpression { } } /*: -### Usage +### 用法 */ var context = IntegerContext() diff --git a/source-cn/behavioral/iterator.swift b/source-cn/behavioral/iterator.swift index d351958..ccc0381 100644 --- a/source-cn/behavioral/iterator.swift +++ b/source-cn/behavioral/iterator.swift @@ -1,10 +1,10 @@ /*: -🍫 Iterator ------------ +🍫 迭代器(Iterator) + --------------- -The iterator pattern is used to provide a standard interface for traversing a collection of items in an aggregate object without the need to understand its underlying structure. - -### Example: + 迭代器模式可以让用户通过特定的接口巡访容器中的每一个元素而不用了解底层的实现。 + + ### 示例: */ struct Novella { let name: String @@ -35,7 +35,7 @@ extension Novellas: Sequence { } } /*: -### Usage +### 用法 */ let greatNovellas = Novellas(novellas: [Novella(name: "The Mist")] ) diff --git a/source-cn/behavioral/mediator.swift b/source-cn/behavioral/mediator.swift index 07648f5..2ae0e6b 100644 --- a/source-cn/behavioral/mediator.swift +++ b/source-cn/behavioral/mediator.swift @@ -1,10 +1,10 @@ /*: -💐 Mediator ------------ +💐 中介者(Mediator) + --------------- -The mediator pattern is used to reduce coupling between classes that communicate with each other. Instead of classes communicating directly, and thus requiring knowledge of their implementation, the classes send messages via a mediator object. + 用一个中介者对象封装一系列的对象交互,中介者使各对象不需要显示地相互作用,从而使耦合松散,而且可以独立地改变它们之间的交互。 -### Example + ### 示例: */ protocol Receiver { associatedtype MessageType @@ -47,7 +47,7 @@ final class MessageMediator: Sender { } /*: -### Usage +### 用法 */ func spamMonster(message: String, worker: MessageMediator) { worker.send(message: message) diff --git a/source-cn/behavioral/memento.swift b/source-cn/behavioral/memento.swift index 13b0474..6bbe9c6 100644 --- a/source-cn/behavioral/memento.swift +++ b/source-cn/behavioral/memento.swift @@ -1,14 +1,14 @@ /*: -💾 Memento ----------- +💾 备忘录(Memento) +-------------- -The memento pattern is used to capture the current state of an object and store it in such a manner that it can be restored at a later time without breaking the rules of encapsulation. +在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样就可以将该对象恢复到原先保存的状态 -### Example +### 示例: */ typealias Memento = [String: String] /*: -Originator +发起人(Originator) */ protocol MementoConvertible { var memento: Memento { get } @@ -45,7 +45,7 @@ struct GameState: MementoConvertible { } } /*: -Caretaker +管理者(Caretaker) */ enum CheckPoint { @@ -61,7 +61,7 @@ enum CheckPoint { } } /*: -### Usage +### 用法 */ var gameState = GameState(chapter: "Black Mesa Inbound", weapon: "Crowbar") diff --git a/source-cn/behavioral/observer.swift b/source-cn/behavioral/observer.swift index aec0ac8..b9e21ec 100644 --- a/source-cn/behavioral/observer.swift +++ b/source-cn/behavioral/observer.swift @@ -1,11 +1,10 @@ /*: -👓 Observer ------------ +👓 观察者(Observer) +--------------- -The observer pattern is used to allow an object to publish changes to its state. -Other objects subscribe to be immediately notified of any changes. +一个目标对象管理所有相依于它的观察者对象,并且在它本身的状态改变时主动发出通知 -### Example +### 示例: */ protocol PropertyObserver : class { func willChange(propertyName: String, newPropertyValue: Any?) @@ -42,7 +41,7 @@ final class Observer : PropertyObserver { } } /*: -### Usage +### 用法 */ var observerInstance = Observer() var testChambers = TestChambers() diff --git a/source-cn/behavioral/state.swift b/source-cn/behavioral/state.swift index 14d84c1..37958f8 100644 --- a/source-cn/behavioral/state.swift +++ b/source-cn/behavioral/state.swift @@ -1,11 +1,11 @@ /*: -🐉 State +🐉 状态(State) --------- -The state pattern is used to alter the behaviour of an object as its internal state changes. -The pattern allows the class for an object to apparently change at run-time. +在状态模式中,对象的行为是基于它的内部状态而改变的。 +这个模式允许某个类对象在运行时发生改变。 -### Example +### 示例: */ final class Context { private var state: State = UnauthorizedState() @@ -48,7 +48,7 @@ class AuthorizedState: State { func userId(context: Context) -> String? { return userId } } /*: -### Usage +### 用法 */ let userContext = Context() (userContext.isAuthorized, userContext.userId) diff --git a/source-cn/behavioral/strategy.swift b/source-cn/behavioral/strategy.swift index f358961..bde6efa 100644 --- a/source-cn/behavioral/strategy.swift +++ b/source-cn/behavioral/strategy.swift @@ -1,10 +1,13 @@ /*: -💡 Strategy ------------ +💡 策略(Strategy) +-------------- -The strategy pattern is used to create an interchangeable family of algorithms from which the required process is chosen at run-time. +对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。策略模式: +* 定义了一族算法(业务规则); +* 封装了每个算法; +* 这族的算法可互换代替(interchangeable)。 -### Example +### 示例: */ struct TestSubject { @@ -42,7 +45,7 @@ final class BladeRunner { } /*: - ### Usage + ### 用法 */ let rachel = TestSubject(pupilDiameter: 30.2, diff --git a/source-cn/behavioral/visitor.swift b/source-cn/behavioral/visitor.swift index d53e409..14513ba 100644 --- a/source-cn/behavioral/visitor.swift +++ b/source-cn/behavioral/visitor.swift @@ -1,10 +1,10 @@ /*: -🏃 Visitor ----------- +🏃 访问者(Visitor) +-------------- -The visitor pattern is used to separate a relatively complex set of structured data classes from the functionality that may be performed upon the data that they hold. +封装某些作用于某种数据结构中各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。 -### Example +### 示例: */ protocol PlanetVisitor { func visit(planet: PlanetAlderaan) @@ -43,7 +43,7 @@ final class NameVisitor: PlanetVisitor { } /*: -### Usage +### 用法 */ let planets: [Planet] = [PlanetAlderaan(), PlanetCoruscant(), PlanetTatooine(), MoonJedha()] diff --git a/source-cn/contents.md b/source-cn/contents.md index 8503238..8b8750e 100644 --- a/source-cn/contents.md +++ b/source-cn/contents.md @@ -1,6 +1,6 @@ -## Table of Contents +## 目录 -* [Behavioral](Behavioral) -* [Creational](Creational) -* [Structural](Structural) +* [行为型模式](Behavioral) +* [创建型模式](Creational) +* [结构型模式](Structural) \ No newline at end of file diff --git a/source-cn/creational/abstract_factory.swift b/source-cn/creational/abstract_factory.swift index 16d2899..4586869 100644 --- a/source-cn/creational/abstract_factory.swift +++ b/source-cn/creational/abstract_factory.swift @@ -1,13 +1,12 @@ /*: -🌰 Abstract Factory -------------------- +🌰 抽象工厂(Abstract Factory) +------------- -The abstract factory pattern is used to provide a client with a set of related or dependant objects. -The "family" of objects created by the factory are determined at run-time. +抽象工厂模式提供了一种方式,可以将一组具有同一主题的单独的工厂封装起来。在正常使用中,客户端程序需要创建抽象工厂的具体实现,然后使用抽象工厂作为接口来创建这一主题的具体对象。 -### Example +### 示例: -Protocols +协议 */ protocol BurgerDescribing { @@ -22,7 +21,7 @@ protocol BurgerMaking { func make() -> BurgerDescribing } -// Number implementations with factory methods +// 工厂方法实现 final class BigKahunaBurger: BurgerMaking { func make() -> BurgerDescribing { @@ -37,7 +36,7 @@ final class JackInTheBox: BurgerMaking { } /*: -Abstract factory +抽象工厂 */ enum BurgerFactoryType: BurgerMaking { @@ -55,7 +54,7 @@ enum BurgerFactoryType: BurgerMaking { } } /*: -### Usage +### 用法 */ let bigKahuna = BurgerFactoryType.bigKahuna.make() let jackInTheBox = BurgerFactoryType.jackInTheBox.make() diff --git a/source-cn/creational/builder.swift b/source-cn/creational/builder.swift index 139139a..4de8bee 100644 --- a/source-cn/creational/builder.swift +++ b/source-cn/creational/builder.swift @@ -1,11 +1,10 @@ /*: -👷 Builder ----------- +👷 生成器(Builder) +-------------- -The builder pattern is used to create complex objects with constituent parts that must be created in the same order or using a specific algorithm. -An external class controls the construction algorithm. +一种对象构建模式。它可以将复杂对象的建造过程抽象出来(抽象类别),使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象。 -### Example +### 示例: */ final class DeathStarBuilder { @@ -42,7 +41,7 @@ struct DeathStar : CustomStringConvertible { } } /*: -### Usage +### 用法 */ let empire = DeathStarBuilder { builder in builder.x = 0.1 diff --git a/source-cn/creational/factory.swift b/source-cn/creational/factory.swift index aeee853..916b40c 100644 --- a/source-cn/creational/factory.swift +++ b/source-cn/creational/factory.swift @@ -1,10 +1,10 @@ /*: -🏭 Factory Method ------------------ +🏭 工厂方法(Factory Method) +----------------------- -The factory pattern is used to replace class constructors, abstracting the process of object generation so that the type of the object instantiated can be determined at run-time. +定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类。工厂方法让类的实例化推迟到子类中进行。 -### Example +### 示例: */ protocol CurrencyDescribing { var symbol: String { get } @@ -53,7 +53,7 @@ enum CurrencyFactory { } } /*: -### Usage +### 用法 */ let noCurrencyCode = "No Currency Code Available" diff --git a/source-cn/creational/header.md b/source-cn/creational/header.md index 1684668..0a553b7 100644 --- a/source-cn/creational/header.md +++ b/source-cn/creational/header.md @@ -1,7 +1,8 @@ -Creational -========== - -> In software engineering, creational design patterns are design patterns that deal with object creation mechanisms, trying to create objects in a manner suitable to the situation. The basic form of object creation could result in design problems or added complexity to the design. Creational design patterns solve this problem by somehow controlling this object creation. -> ->**Source:** [wikipedia.org](http://en.wikipedia.org/wiki/Creational_pattern) + 创建型模式 + ======== + + > 创建型模式是处理对象创建的设计模式,试图根据实际情况使用合适的方式创建对象。基本的对象创建方式可能会导致设计上的问题,或增加设计的复杂度。创建型模式通过以某种方式控制对象的创建来解决问题。 + > + >**来源:** [维基百科](https://zh.wikipedia.org/wiki/%E5%89%B5%E5%BB%BA%E5%9E%8B%E6%A8%A1%E5%BC%8F) + \ No newline at end of file diff --git a/source-cn/creational/prototype.swift b/source-cn/creational/prototype.swift index 7840489..c98ccf5 100644 --- a/source-cn/creational/prototype.swift +++ b/source-cn/creational/prototype.swift @@ -1,11 +1,10 @@ /*: -🃏 Prototype ------------- +🃏 原型(Prototype) +-------------- -The prototype pattern is used to instantiate a new object by copying all of the properties of an existing object, creating an independent clone. -This practise is particularly useful when the construction of a new object is inefficient. +通过“复制”一个已经存在的实例来返回新的实例,而不是新建实例。被复制的实例就是我们所称的“原型”,这个原型是可定制的。 -### Example +### 示例: */ struct MoonWorker { @@ -21,7 +20,7 @@ struct MoonWorker { } } /*: -### Usage +### 用法 */ let prototype = MoonWorker(name: "Sam Bell") diff --git a/source-cn/creational/singleton.swift b/source-cn/creational/singleton.swift index 539bca5..719360d 100644 --- a/source-cn/creational/singleton.swift +++ b/source-cn/creational/singleton.swift @@ -1,12 +1,10 @@ /*: -💍 Singleton ------------- +💍 单例(Singleton) +-------------- -The singleton pattern ensures that only one object of a particular class is ever created. -All further references to objects of the singleton class refer to the same underlying instance. -There are very few applications, do not overuse this pattern! +单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为 -### Example: +### 示例: */ final class ElonMusk { @@ -17,6 +15,6 @@ final class ElonMusk { } } /*: -### Usage: +### 用法 */ let elon = ElonMusk.shared // There is only one Elon Musk folks. diff --git a/source-cn/structural/adapter.swift b/source-cn/structural/adapter.swift index 3a99081..c654c03 100644 --- a/source-cn/structural/adapter.swift +++ b/source-cn/structural/adapter.swift @@ -1,17 +1,17 @@ /*: -🔌 Adapter ----------- +🔌 适配器(Adapter) +-------------- -The adapter pattern is used to provide a link between two otherwise incompatible types by wrapping the "adaptee" with a class that supports the interface required by the client. +适配器模式有时候也称包装样式或者包装(wrapper)。将一个类的接口转接成用户所期待的。一个适配使得因接口不兼容而不能在一起工作的类工作在一起,做法是将类自己的接口包裹在一个已存在的类中。 -### Example +### 示例: */ protocol NewDeathStarSuperLaserAiming { var angleV: Double { get } var angleH: Double { get } } /*: -**Adaptee** +**被适配者** */ struct OldDeathStarSuperlaserTarget { let angleHorizontal: Float @@ -23,7 +23,7 @@ struct OldDeathStarSuperlaserTarget { } } /*: -**Adapter** +**适配器** */ struct NewDeathStarSuperlaserTarget: NewDeathStarSuperLaserAiming { @@ -42,7 +42,7 @@ struct NewDeathStarSuperlaserTarget: NewDeathStarSuperLaserAiming { } } /*: -### Usage +### 用法 */ let target = OldDeathStarSuperlaserTarget(angleHorizontal: 14.0, angleVertical: 12.0) let newFormat = NewDeathStarSuperlaserTarget(target) diff --git a/source-cn/structural/bridge.swift b/source-cn/structural/bridge.swift index 2384c7e..e9f8979 100644 --- a/source-cn/structural/bridge.swift +++ b/source-cn/structural/bridge.swift @@ -1,10 +1,10 @@ /*: -🌉 Bridge ----------- +🌉 桥接(Bridge) +----------- -The bridge pattern is used to separate the abstract elements of a class from the implementation details, providing the means to replace the implementation details without modifying the abstraction. +桥接模式将抽象部分与实现部分分离,使它们都可以独立的变化。 -### Example +### 示例: */ protocol Switch { var appliance: Appliance { get set } @@ -39,7 +39,7 @@ final class VacuumCleaner: Appliance { } } /*: -### Usage +### 用法 */ let tvRemoteControl = RemoteControl(appliance: TV()) tvRemoteControl.turnOn() diff --git a/source-cn/structural/composite.swift b/source-cn/structural/composite.swift index 522cd7c..8d771e2 100644 --- a/source-cn/structural/composite.swift +++ b/source-cn/structural/composite.swift @@ -1,18 +1,18 @@ /*: -🌿 Composite -------------- +🌿 组合(Composite) +-------------- -The composite pattern is used to create hierarchical, recursive tree structures of related objects where any element of the structure may be accessed and utilised in a standard manner. +将对象组合成树形结构以表示‘部分-整体’的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。 -### Example +### 示例: -Component +组件(Component) */ protocol Shape { func draw(fillColor: String) } /*: -Leafs +叶子节点(Leafs) */ final class Square: Shape { func draw(fillColor: String) { @@ -27,7 +27,7 @@ final class Circle: Shape { } /*: -Composite +组合 */ final class Whiteboard: Shape { @@ -44,7 +44,7 @@ final class Whiteboard: Shape { } } /*: -### Usage: +### 用法 */ var whiteboard = Whiteboard(Circle(), Square()) whiteboard.draw(fillColor: "Red") diff --git a/source-cn/structural/decorator.swift b/source-cn/structural/decorator.swift index c531d1e..7b47e39 100644 --- a/source-cn/structural/decorator.swift +++ b/source-cn/structural/decorator.swift @@ -1,11 +1,11 @@ /*: -🍧 Decorator ------------- +🍧 修饰(Decorator) +-------------- -The decorator pattern is used to extend or alter the functionality of objects at run- time by wrapping them in an object of a decorator class. -This provides a flexible alternative to using inheritance to modify behaviour. +修饰模式,是面向对象编程领域中,一种动态地往一个类中添加新的行为的设计模式。 +就功能而言,修饰模式相比生成子类更为灵活,这样可以给某个对象而不是整个类添加一些功能。 -### Example +### 示例: */ protocol CostHaving { var cost: Double { get } @@ -52,7 +52,7 @@ struct WhipCoffee: BeverageHaving { } } /*: -### Usage: +### 用法 */ var someCoffee: BeverageDataHaving = SimpleCoffee() print("Cost: \(someCoffee.cost); Ingredients: \(someCoffee.ingredients)") diff --git a/source-cn/structural/facade.swift b/source-cn/structural/facade.swift index 1147d57..f9a3b42 100644 --- a/source-cn/structural/facade.swift +++ b/source-cn/structural/facade.swift @@ -1,10 +1,10 @@ /*: -🎁 Façade ---------- +🎁 外观(Facade) +----------- -The facade pattern is used to define a simplified interface to a more complex subsystem. +外观模式为子系统中的一组接口提供一个统一的高层接口,使得子系统更容易使用。 -### Example +### 示例: */ final class Defaults { @@ -25,7 +25,7 @@ final class Defaults { } } /*: -### Usage +### 用法 */ let storage = Defaults() diff --git a/source-cn/structural/flyweight.swift b/source-cn/structural/flyweight.swift index 3a2d944..fe90a60 100644 --- a/source-cn/structural/flyweight.swift +++ b/source-cn/structural/flyweight.swift @@ -12,7 +12,7 @@ protocol CoffeeSearching { func search(origin: String) -> SpecialityCoffee? } -// Menu acts as a factory and cache for SpecialityCoffee flyweight objects +// 菜单充当特制咖啡享元对象的工厂和缓存 final class Menu: CoffeeSearching { private var coffeeAvailable: [String: SpecialityCoffee] = [:] @@ -45,7 +45,7 @@ final class CoffeeShop { } } /*: -### Usage +### 用法 */ let coffeeShop = CoffeeShop(menu: Menu()) diff --git a/source-cn/structural/header.md b/source-cn/structural/header.md index 67cdc66..7b27407 100644 --- a/source-cn/structural/header.md +++ b/source-cn/structural/header.md @@ -1,7 +1,7 @@ -Structural -========== +结构型模式(Structural) +==================== ->In software engineering, structural design patterns are design patterns that ease the design by identifying a simple way to realize relationships between entities. +> 在软件工程中结构型模式是设计模式,借由一以贯之的方式来了解元件间的关系,以简化设计。 > ->**Source:** [wikipedia.org](http://en.wikipedia.org/wiki/Structural_pattern) +>**来源:** [维基百科](https://zh.wikipedia.org/wiki/%E7%B5%90%E6%A7%8B%E5%9E%8B%E6%A8%A1%E5%BC%8F) diff --git a/source-cn/structural/protection_proxy.swift b/source-cn/structural/protection_proxy.swift index f012f47..dcb519e 100644 --- a/source-cn/structural/protection_proxy.swift +++ b/source-cn/structural/protection_proxy.swift @@ -1,11 +1,11 @@ /*: -☔ Protection Proxy +☔ 保护代理模式(Protection Proxy) ------------------ -The proxy pattern is used to provide a surrogate or placeholder object, which references an underlying object. -Protection proxy is restricting access. +在代理模式中,创建一个类代表另一个底层类的功能。 +保护代理用于限制访问。 -### Example +### 示例: */ protocol DoorOpening { func open(doors: String) -> String @@ -41,7 +41,7 @@ final class CurrentComputer: DoorOpening { } } /*: -### Usage +### 用法 */ let computer = CurrentComputer() let podBay = "Pod Bay Doors" diff --git a/source-cn/structural/virtual_proxy.swift b/source-cn/structural/virtual_proxy.swift index 9a02414..c17233a 100644 --- a/source-cn/structural/virtual_proxy.swift +++ b/source-cn/structural/virtual_proxy.swift @@ -1,11 +1,11 @@ /*: -🍬 Virtual Proxy +🍬 虚拟代理(Virtual Proxy) ---------------- -The proxy pattern is used to provide a surrogate or placeholder object, which references an underlying object. -Virtual proxy is used for loading object on demand. +在代理模式中,创建一个类代表另一个底层类的功能。 +虚拟代理用于对象的需时加载。 -### Example +### 示例: */ protocol HEVSuitMedicalAid { func administerMorphine() -> String @@ -26,7 +26,7 @@ final class HEVSuitHumanInterface: HEVSuitMedicalAid { } } /*: -### Usage +### 用法 */ let humanInterface = HEVSuitHumanInterface() humanInterface.administerMorphine() From 48dfc5b245b6f477ed2d46148c5305b835ccfcff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=85=B4=E5=BD=AC=5FBinboy?= Date: Fri, 13 Mar 2020 23:07:39 +0800 Subject: [PATCH 26/66] Generate chinese version --- Design-Patterns-CN.playground.zip | Bin 0 -> 24340 bytes .../Contents.swift | 677 ++++++++++++++++++ .../Contents.swift | 251 +++++++ .../Index.xcplaygroundpage/Contents.swift | 21 + .../Contents.swift | 403 +++++++++++ .../timeline.xctimeline | 6 + .../contents.xcplayground | 9 + README.md | 312 ++++---- 8 files changed, 1520 insertions(+), 159 deletions(-) create mode 100644 Design-Patterns-CN.playground.zip create mode 100644 Design-Patterns-CN.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift create mode 100644 Design-Patterns-CN.playground/Pages/Creational.xcplaygroundpage/Contents.swift create mode 100644 Design-Patterns-CN.playground/Pages/Index.xcplaygroundpage/Contents.swift create mode 100644 Design-Patterns-CN.playground/Pages/Structural.xcplaygroundpage/Contents.swift create mode 100644 Design-Patterns-CN.playground/Pages/Structural.xcplaygroundpage/timeline.xctimeline create mode 100644 Design-Patterns-CN.playground/contents.xcplayground diff --git a/Design-Patterns-CN.playground.zip b/Design-Patterns-CN.playground.zip new file mode 100644 index 0000000000000000000000000000000000000000..01877beb2f74f678df7c2e3438a23fd9c450d25e GIT binary patch literal 24340 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 software engineering, behavioral design patterns are design patterns that identify common communication patterns between objects and realize these patterns. By doing so, these patterns increase flexibility in carrying out this communication. +> +>**Source:** [wikipedia.org](http://en.wikipedia.org/wiki/Behavioral_pattern) + +## Table of Contents + +* [Behavioral](Behavioral) +* [Creational](Creational) +* [Structural](Structural) + +*/ +import Foundation +/*: +🐝 Chain Of Responsibility +-------------------------- + +The chain of responsibility pattern is used to process varied requests, each of which may be dealt with by a different handler. + +### Example: +*/ + +protocol Withdrawing { + func withdraw(amount: Int) -> Bool +} + +final class MoneyPile: Withdrawing { + + let value: Int + var quantity: Int + var next: Withdrawing? + + init(value: Int, quantity: Int, next: Withdrawing?) { + self.value = value + self.quantity = quantity + self.next = next + } + + func withdraw(amount: Int) -> Bool { + + var amount = amount + + func canTakeSomeBill(want: Int) -> Bool { + return (want / self.value) > 0 + } + + var quantity = self.quantity + + while canTakeSomeBill(want: amount) { + + if quantity == 0 { + break + } + + amount -= self.value + quantity -= 1 + } + + guard amount > 0 else { + return true + } + + if let next = self.next { + return next.withdraw(amount: amount) + } + + return false + } +} + +final class ATM: Withdrawing { + + private var hundred: Withdrawing + private var fifty: Withdrawing + private var twenty: Withdrawing + private var ten: Withdrawing + + private var startPile: Withdrawing { + return self.hundred + } + + init(hundred: Withdrawing, + fifty: Withdrawing, + twenty: Withdrawing, + ten: Withdrawing) { + + self.hundred = hundred + self.fifty = fifty + self.twenty = twenty + self.ten = ten + } + + func withdraw(amount: Int) -> Bool { + return startPile.withdraw(amount: amount) + } +} +/*: +### Usage +*/ +// Create piles of money and link them together 10 < 20 < 50 < 100.** +let ten = MoneyPile(value: 10, quantity: 6, next: nil) +let twenty = MoneyPile(value: 20, quantity: 2, next: ten) +let fifty = MoneyPile(value: 50, quantity: 2, next: twenty) +let hundred = MoneyPile(value: 100, quantity: 1, next: fifty) + +// Build ATM. +var atm = ATM(hundred: hundred, fifty: fifty, twenty: twenty, ten: ten) +atm.withdraw(amount: 310) // Cannot because ATM has only 300 +atm.withdraw(amount: 100) // Can withdraw - 1x100 +/*: +👫 Command +---------- + +The command pattern is used to express a request, including the call to be made and all of its required parameters, in a command object. The command may then be executed immediately or held for later use. + +### Example: +*/ +protocol DoorCommand { + func execute() -> String +} + +final class OpenCommand: DoorCommand { + let doors:String + + required init(doors: String) { + self.doors = doors + } + + func execute() -> String { + return "Opened \(doors)" + } +} + +final class CloseCommand: DoorCommand { + let doors:String + + required init(doors: String) { + self.doors = doors + } + + func execute() -> String { + return "Closed \(doors)" + } +} + +final class HAL9000DoorsOperations { + let openCommand: DoorCommand + let closeCommand: DoorCommand + + init(doors: String) { + self.openCommand = OpenCommand(doors:doors) + self.closeCommand = CloseCommand(doors:doors) + } + + func close() -> String { + return closeCommand.execute() + } + + func open() -> String { + return openCommand.execute() + } +} +/*: +### Usage: +*/ +let podBayDoors = "Pod Bay Doors" +let doorModule = HAL9000DoorsOperations(doors:podBayDoors) + +doorModule.open() +doorModule.close() +/*: +🎶 Interpreter +-------------- + +The interpreter pattern is used to evaluate sentences in a language. + +### Example +*/ + +protocol IntegerExpression { + func evaluate(_ context: IntegerContext) -> Int + func replace(character: Character, integerExpression: IntegerExpression) -> IntegerExpression + func copied() -> IntegerExpression +} + +final class IntegerContext { + private var data: [Character:Int] = [:] + + func lookup(name: Character) -> Int { + return self.data[name]! + } + + func assign(expression: IntegerVariableExpression, value: Int) { + self.data[expression.name] = value + } +} + +final class IntegerVariableExpression: IntegerExpression { + let name: Character + + init(name: Character) { + self.name = name + } + + func evaluate(_ context: IntegerContext) -> Int { + return context.lookup(name: self.name) + } + + func replace(character name: Character, integerExpression: IntegerExpression) -> IntegerExpression { + if name == self.name { + return integerExpression.copied() + } else { + return IntegerVariableExpression(name: self.name) + } + } + + func copied() -> IntegerExpression { + return IntegerVariableExpression(name: self.name) + } +} + +final class AddExpression: IntegerExpression { + private var operand1: IntegerExpression + private var operand2: IntegerExpression + + init(op1: IntegerExpression, op2: IntegerExpression) { + self.operand1 = op1 + self.operand2 = op2 + } + + func evaluate(_ context: IntegerContext) -> Int { + return self.operand1.evaluate(context) + self.operand2.evaluate(context) + } + + func replace(character: Character, integerExpression: IntegerExpression) -> IntegerExpression { + return AddExpression(op1: operand1.replace(character: character, integerExpression: integerExpression), + op2: operand2.replace(character: character, integerExpression: integerExpression)) + } + + func copied() -> IntegerExpression { + return AddExpression(op1: self.operand1, op2: self.operand2) + } +} +/*: +### Usage +*/ +var context = IntegerContext() + +var a = IntegerVariableExpression(name: "A") +var b = IntegerVariableExpression(name: "B") +var c = IntegerVariableExpression(name: "C") + +var expression = AddExpression(op1: a, op2: AddExpression(op1: b, op2: c)) // a + (b + c) + +context.assign(expression: a, value: 2) +context.assign(expression: b, value: 1) +context.assign(expression: c, value: 3) + +var result = expression.evaluate(context) +/*: +🍫 Iterator +----------- + +The iterator pattern is used to provide a standard interface for traversing a collection of items in an aggregate object without the need to understand its underlying structure. + +### Example: +*/ +struct Novella { + let name: String +} + +struct Novellas { + let novellas: [Novella] +} + +struct NovellasIterator: IteratorProtocol { + + private var current = 0 + private let novellas: [Novella] + + init(novellas: [Novella]) { + self.novellas = novellas + } + + mutating func next() -> Novella? { + defer { current += 1 } + return novellas.count > current ? novellas[current] : nil + } +} + +extension Novellas: Sequence { + func makeIterator() -> NovellasIterator { + return NovellasIterator(novellas: novellas) + } +} +/*: +### Usage +*/ +let greatNovellas = Novellas(novellas: [Novella(name: "The Mist")] ) + +for novella in greatNovellas { + print("I've read: \(novella)") +} +/*: +💐 Mediator +----------- + +The mediator pattern is used to reduce coupling between classes that communicate with each other. Instead of classes communicating directly, and thus requiring knowledge of their implementation, the classes send messages via a mediator object. + +### Example +*/ +protocol Receiver { + associatedtype MessageType + func receive(message: MessageType) +} + +protocol Sender { + associatedtype MessageType + associatedtype ReceiverType: Receiver + + var recipients: [ReceiverType] { get } + + func send(message: MessageType) +} + +struct Programmer: Receiver { + let name: String + + init(name: String) { + self.name = name + } + + func receive(message: String) { + print("\(name) received: \(message)") + } +} + +final class MessageMediator: Sender { + internal var recipients: [Programmer] = [] + + func add(recipient: Programmer) { + recipients.append(recipient) + } + + func send(message: String) { + for recipient in recipients { + recipient.receive(message: message) + } + } +} + +/*: +### Usage +*/ +func spamMonster(message: String, worker: MessageMediator) { + worker.send(message: message) +} + +let messagesMediator = MessageMediator() + +let user0 = Programmer(name: "Linus Torvalds") +let user1 = Programmer(name: "Avadis 'Avie' Tevanian") +messagesMediator.add(recipient: user0) +messagesMediator.add(recipient: user1) + +spamMonster(message: "I'd Like to Add you to My Professional Network", worker: messagesMediator) + +/*: +💾 Memento +---------- + +The memento pattern is used to capture the current state of an object and store it in such a manner that it can be restored at a later time without breaking the rules of encapsulation. + +### Example +*/ +typealias Memento = [String: String] +/*: +Originator +*/ +protocol MementoConvertible { + var memento: Memento { get } + init?(memento: Memento) +} + +struct GameState: MementoConvertible { + + private enum Keys { + static let chapter = "com.valve.halflife.chapter" + static let weapon = "com.valve.halflife.weapon" + } + + var chapter: String + var weapon: String + + init(chapter: String, weapon: String) { + self.chapter = chapter + self.weapon = weapon + } + + init?(memento: Memento) { + guard let mementoChapter = memento[Keys.chapter], + let mementoWeapon = memento[Keys.weapon] else { + return nil + } + + chapter = mementoChapter + weapon = mementoWeapon + } + + var memento: Memento { + return [ Keys.chapter: chapter, Keys.weapon: weapon ] + } +} +/*: +Caretaker +*/ +enum CheckPoint { + + private static let defaults = UserDefaults.standard + + static func save(_ state: MementoConvertible, saveName: String) { + defaults.set(state.memento, forKey: saveName) + defaults.synchronize() + } + + static func restore(saveName: String) -> Any? { + return defaults.object(forKey: saveName) + } +} +/*: +### Usage +*/ +var gameState = GameState(chapter: "Black Mesa Inbound", weapon: "Crowbar") + +gameState.chapter = "Anomalous Materials" +gameState.weapon = "Glock 17" +CheckPoint.save(gameState, saveName: "gameState1") + +gameState.chapter = "Unforeseen Consequences" +gameState.weapon = "MP5" +CheckPoint.save(gameState, saveName: "gameState2") + +gameState.chapter = "Office Complex" +gameState.weapon = "Crossbow" +CheckPoint.save(gameState, saveName: "gameState3") + +if let memento = CheckPoint.restore(saveName: "gameState1") as? Memento { + let finalState = GameState(memento: memento) + dump(finalState) +} +/*: +👓 Observer +----------- + +The observer pattern is used to allow an object to publish changes to its state. +Other objects subscribe to be immediately notified of any changes. + +### Example +*/ +protocol PropertyObserver : class { + func willChange(propertyName: String, newPropertyValue: Any?) + func didChange(propertyName: String, oldPropertyValue: Any?) +} + +final class TestChambers { + + weak var observer:PropertyObserver? + + private let testChamberNumberName = "testChamberNumber" + + var testChamberNumber: Int = 0 { + willSet(newValue) { + observer?.willChange(propertyName: testChamberNumberName, newPropertyValue: newValue) + } + didSet { + observer?.didChange(propertyName: testChamberNumberName, oldPropertyValue: oldValue) + } + } +} + +final class Observer : PropertyObserver { + func willChange(propertyName: String, newPropertyValue: Any?) { + if newPropertyValue as? Int == 1 { + print("Okay. Look. We both said a lot of things that you're going to regret.") + } + } + + func didChange(propertyName: String, oldPropertyValue: Any?) { + if oldPropertyValue as? Int == 0 { + print("Sorry about the mess. I've really let the place go since you killed me.") + } + } +} +/*: +### Usage +*/ +var observerInstance = Observer() +var testChambers = TestChambers() +testChambers.observer = observerInstance +testChambers.testChamberNumber += 1 +/*: +🐉 State +--------- + +The state pattern is used to alter the behaviour of an object as its internal state changes. +The pattern allows the class for an object to apparently change at run-time. + +### Example +*/ +final class Context { + private var state: State = UnauthorizedState() + + var isAuthorized: Bool { + get { return state.isAuthorized(context: self) } + } + + var userId: String? { + get { return state.userId(context: self) } + } + + func changeStateToAuthorized(userId: String) { + state = AuthorizedState(userId: userId) + } + + func changeStateToUnauthorized() { + state = UnauthorizedState() + } +} + +protocol State { + func isAuthorized(context: Context) -> Bool + func userId(context: Context) -> String? +} + +class UnauthorizedState: State { + func isAuthorized(context: Context) -> Bool { return false } + + func userId(context: Context) -> String? { return nil } +} + +class AuthorizedState: State { + let userId: String + + init(userId: String) { self.userId = userId } + + func isAuthorized(context: Context) -> Bool { return true } + + func userId(context: Context) -> String? { return userId } +} +/*: +### Usage +*/ +let userContext = Context() +(userContext.isAuthorized, userContext.userId) +userContext.changeStateToAuthorized(userId: "admin") +(userContext.isAuthorized, userContext.userId) // now logged in as "admin" +userContext.changeStateToUnauthorized() +(userContext.isAuthorized, userContext.userId) +/*: +💡 Strategy +----------- + +The strategy pattern is used to create an interchangeable family of algorithms from which the required process is chosen at run-time. + +### Example +*/ + +struct TestSubject { + let pupilDiameter: Double + let blushResponse: Double + let isOrganic: Bool +} + +protocol RealnessTesting: AnyObject { + func testRealness(_ testSubject: TestSubject) -> Bool +} + +final class VoightKampffTest: RealnessTesting { + func testRealness(_ testSubject: TestSubject) -> Bool { + return testSubject.pupilDiameter < 30.0 || testSubject.blushResponse == 0.0 + } +} + +final class GeneticTest: RealnessTesting { + func testRealness(_ testSubject: TestSubject) -> Bool { + return testSubject.isOrganic + } +} + +final class BladeRunner { + private let strategy: RealnessTesting + + init(test: RealnessTesting) { + self.strategy = test + } + + func testIfAndroid(_ testSubject: TestSubject) -> Bool { + return !strategy.testRealness(testSubject) + } +} + +/*: + ### Usage + */ + +let rachel = TestSubject(pupilDiameter: 30.2, + blushResponse: 0.3, + isOrganic: false) + +// Deckard is using a traditional test +let deckard = BladeRunner(test: VoightKampffTest()) +let isRachelAndroid = deckard.testIfAndroid(rachel) + +// Gaff is using a very precise method +let gaff = BladeRunner(test: GeneticTest()) +let isDeckardAndroid = gaff.testIfAndroid(rachel) +/*: +🏃 Visitor +---------- + +The visitor pattern is used to separate a relatively complex set of structured data classes from the functionality that may be performed upon the data that they hold. + +### Example +*/ +protocol PlanetVisitor { + func visit(planet: PlanetAlderaan) + func visit(planet: PlanetCoruscant) + func visit(planet: PlanetTatooine) + func visit(planet: MoonJedha) +} + +protocol Planet { + func accept(visitor: PlanetVisitor) +} + +final class MoonJedha: Planet { + func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) } +} + +final class PlanetAlderaan: Planet { + func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) } +} + +final class PlanetCoruscant: Planet { + func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) } +} + +final class PlanetTatooine: Planet { + func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) } +} + +final class NameVisitor: PlanetVisitor { + var name = "" + + func visit(planet: PlanetAlderaan) { name = "Alderaan" } + func visit(planet: PlanetCoruscant) { name = "Coruscant" } + func visit(planet: PlanetTatooine) { name = "Tatooine" } + func visit(planet: MoonJedha) { name = "Jedha" } +} + +/*: +### Usage +*/ +let planets: [Planet] = [PlanetAlderaan(), PlanetCoruscant(), PlanetTatooine(), MoonJedha()] + +let names = planets.map { (planet: Planet) -> String in + let visitor = NameVisitor() + planet.accept(visitor: visitor) + + return visitor.name +} + +names diff --git a/Design-Patterns-CN.playground/Pages/Creational.xcplaygroundpage/Contents.swift b/Design-Patterns-CN.playground/Pages/Creational.xcplaygroundpage/Contents.swift new file mode 100644 index 0000000..6b46311 --- /dev/null +++ b/Design-Patterns-CN.playground/Pages/Creational.xcplaygroundpage/Contents.swift @@ -0,0 +1,251 @@ +/*: + +Creational +========== + +> In software engineering, creational design patterns are design patterns that deal with object creation mechanisms, trying to create objects in a manner suitable to the situation. The basic form of object creation could result in design problems or added complexity to the design. Creational design patterns solve this problem by somehow controlling this object creation. +> +>**Source:** [wikipedia.org](http://en.wikipedia.org/wiki/Creational_pattern) + +## Table of Contents + +* [Behavioral](Behavioral) +* [Creational](Creational) +* [Structural](Structural) + +*/ +import Foundation +/*: +🌰 Abstract Factory +------------------- + +The abstract factory pattern is used to provide a client with a set of related or dependant objects. +The "family" of objects created by the factory are determined at run-time. + +### Example + +Protocols +*/ + +protocol BurgerDescribing { + var ingredients: [String] { get } +} + +struct CheeseBurger: BurgerDescribing { + let ingredients: [String] +} + +protocol BurgerMaking { + func make() -> BurgerDescribing +} + +// Number implementations with factory methods + +final class BigKahunaBurger: BurgerMaking { + func make() -> BurgerDescribing { + return CheeseBurger(ingredients: ["Cheese", "Burger", "Lettuce", "Tomato"]) + } +} + +final class JackInTheBox: BurgerMaking { + func make() -> BurgerDescribing { + return CheeseBurger(ingredients: ["Cheese", "Burger", "Tomato", "Onions"]) + } +} + +/*: +Abstract factory +*/ + +enum BurgerFactoryType: BurgerMaking { + + case bigKahuna + case jackInTheBox + + func make() -> BurgerDescribing { + switch self { + case .bigKahuna: + return BigKahunaBurger().make() + case .jackInTheBox: + return JackInTheBox().make() + } + } +} +/*: +### Usage +*/ +let bigKahuna = BurgerFactoryType.bigKahuna.make() +let jackInTheBox = BurgerFactoryType.jackInTheBox.make() +/*: +👷 Builder +---------- + +The builder pattern is used to create complex objects with constituent parts that must be created in the same order or using a specific algorithm. +An external class controls the construction algorithm. + +### Example +*/ +final class DeathStarBuilder { + + var x: Double? + var y: Double? + var z: Double? + + typealias BuilderClosure = (DeathStarBuilder) -> () + + init(buildClosure: BuilderClosure) { + buildClosure(self) + } +} + +struct DeathStar : CustomStringConvertible { + + let x: Double + let y: Double + let z: Double + + init?(builder: DeathStarBuilder) { + + if let x = builder.x, let y = builder.y, let z = builder.z { + self.x = x + self.y = y + self.z = z + } else { + return nil + } + } + + var description:String { + return "Death Star at (x:\(x) y:\(y) z:\(z))" + } +} +/*: +### Usage +*/ +let empire = DeathStarBuilder { builder in + builder.x = 0.1 + builder.y = 0.2 + builder.z = 0.3 +} + +let deathStar = DeathStar(builder:empire) +/*: +🏭 Factory Method +----------------- + +The factory pattern is used to replace class constructors, abstracting the process of object generation so that the type of the object instantiated can be determined at run-time. + +### Example +*/ +protocol CurrencyDescribing { + var symbol: String { get } + var code: String { get } +} + +final class Euro: CurrencyDescribing { + var symbol: String { + return "€" + } + + var code: String { + return "EUR" + } +} + +final class UnitedStatesDolar: CurrencyDescribing { + var symbol: String { + return "$" + } + + var code: String { + return "USD" + } +} + +enum Country { + case unitedStates + case spain + case uk + case greece +} + +enum CurrencyFactory { + static func currency(for country: Country) -> CurrencyDescribing? { + + switch country { + case .spain, .greece: + return Euro() + case .unitedStates: + return UnitedStatesDolar() + default: + return nil + } + + } +} +/*: +### Usage +*/ +let noCurrencyCode = "No Currency Code Available" + +CurrencyFactory.currency(for: .greece)?.code ?? noCurrencyCode +CurrencyFactory.currency(for: .spain)?.code ?? noCurrencyCode +CurrencyFactory.currency(for: .unitedStates)?.code ?? noCurrencyCode +CurrencyFactory.currency(for: .uk)?.code ?? noCurrencyCode +/*: +🃏 Prototype +------------ + +The prototype pattern is used to instantiate a new object by copying all of the properties of an existing object, creating an independent clone. +This practise is particularly useful when the construction of a new object is inefficient. + +### Example +*/ +struct MoonWorker { + + let name: String + var health: Int = 100 + + init(name: String) { + self.name = name + } + + func clone() -> MoonWorker { + return MoonWorker(name: name) + } +} +/*: +### Usage +*/ +let prototype = MoonWorker(name: "Sam Bell") + +var bell1 = prototype.clone() +bell1.health = 12 + +var bell2 = prototype.clone() +bell2.health = 23 + +var bell3 = prototype.clone() +bell3.health = 0 +/*: +💍 Singleton +------------ + +The singleton pattern ensures that only one object of a particular class is ever created. +All further references to objects of the singleton class refer to the same underlying instance. +There are very few applications, do not overuse this pattern! + +### Example: +*/ +final class ElonMusk { + + static let shared = ElonMusk() + + private init() { + // Private initialization to ensure just one instance is created. + } +} +/*: +### Usage: +*/ +let elon = ElonMusk.shared // There is only one Elon Musk folks. diff --git a/Design-Patterns-CN.playground/Pages/Index.xcplaygroundpage/Contents.swift b/Design-Patterns-CN.playground/Pages/Index.xcplaygroundpage/Contents.swift new file mode 100644 index 0000000..4a54f9f --- /dev/null +++ b/Design-Patterns-CN.playground/Pages/Index.xcplaygroundpage/Contents.swift @@ -0,0 +1,21 @@ +/*: + +Design Patterns implemented in Swift 5.0 +======================================== + +A short cheat-sheet with Xcode 10.2 Playground ([Design-Patterns.playground.zip](https://raw.githubusercontent.com/ochococo/Design-Patterns-In-Swift/master/Design-Patterns.playground.zip)). + +👷 Project maintained by: [@nsmeme](http://twitter.com/nsmeme) (Oktawian Chojnacki) + +🚀 How to generate README, Playground and zip from source: [GENERATE.md](https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/GENERATE.md) + +## Table of Contents + +* [Behavioral](Behavioral) +* [Creational](Creational) +* [Structural](Structural) + +*/ +import Foundation + +print("Welcome!") diff --git a/Design-Patterns-CN.playground/Pages/Structural.xcplaygroundpage/Contents.swift b/Design-Patterns-CN.playground/Pages/Structural.xcplaygroundpage/Contents.swift new file mode 100644 index 0000000..29c0ef1 --- /dev/null +++ b/Design-Patterns-CN.playground/Pages/Structural.xcplaygroundpage/Contents.swift @@ -0,0 +1,403 @@ +/*: + +Structural +========== + +>In software engineering, structural design patterns are design patterns that ease the design by identifying a simple way to realize relationships between entities. +> +>**Source:** [wikipedia.org](http://en.wikipedia.org/wiki/Structural_pattern) + +## Table of Contents + +* [Behavioral](Behavioral) +* [Creational](Creational) +* [Structural](Structural) + +*/ +import Foundation +/*: +🔌 Adapter +---------- + +The adapter pattern is used to provide a link between two otherwise incompatible types by wrapping the "adaptee" with a class that supports the interface required by the client. + +### Example +*/ +protocol NewDeathStarSuperLaserAiming { + var angleV: Double { get } + var angleH: Double { get } +} +/*: +**Adaptee** +*/ +struct OldDeathStarSuperlaserTarget { + let angleHorizontal: Float + let angleVertical: Float + + init(angleHorizontal: Float, angleVertical: Float) { + self.angleHorizontal = angleHorizontal + self.angleVertical = angleVertical + } +} +/*: +**Adapter** +*/ +struct NewDeathStarSuperlaserTarget: NewDeathStarSuperLaserAiming { + + private let target: OldDeathStarSuperlaserTarget + + var angleV: Double { + return Double(target.angleVertical) + } + + var angleH: Double { + return Double(target.angleHorizontal) + } + + init(_ target: OldDeathStarSuperlaserTarget) { + self.target = target + } +} +/*: +### Usage +*/ +let target = OldDeathStarSuperlaserTarget(angleHorizontal: 14.0, angleVertical: 12.0) +let newFormat = NewDeathStarSuperlaserTarget(target) + +newFormat.angleH +newFormat.angleV +/*: +🌉 Bridge +---------- + +The bridge pattern is used to separate the abstract elements of a class from the implementation details, providing the means to replace the implementation details without modifying the abstraction. + +### Example +*/ +protocol Switch { + var appliance: Appliance { get set } + func turnOn() +} + +protocol Appliance { + func run() +} + +final class RemoteControl: Switch { + var appliance: Appliance + + func turnOn() { + self.appliance.run() + } + + init(appliance: Appliance) { + self.appliance = appliance + } +} + +final class TV: Appliance { + func run() { + print("tv turned on"); + } +} + +final class VacuumCleaner: Appliance { + func run() { + print("vacuum cleaner turned on") + } +} +/*: +### Usage +*/ +let tvRemoteControl = RemoteControl(appliance: TV()) +tvRemoteControl.turnOn() + +let fancyVacuumCleanerRemoteControl = RemoteControl(appliance: VacuumCleaner()) +fancyVacuumCleanerRemoteControl.turnOn() +/*: +🌿 Composite +------------- + +The composite pattern is used to create hierarchical, recursive tree structures of related objects where any element of the structure may be accessed and utilised in a standard manner. + +### Example + +Component +*/ +protocol Shape { + func draw(fillColor: String) +} +/*: +Leafs +*/ +final class Square: Shape { + func draw(fillColor: String) { + print("Drawing a Square with color \(fillColor)") + } +} + +final class Circle: Shape { + func draw(fillColor: String) { + print("Drawing a circle with color \(fillColor)") + } +} + +/*: +Composite +*/ +final class Whiteboard: Shape { + + private lazy var shapes = [Shape]() + + init(_ shapes: Shape...) { + self.shapes = shapes + } + + func draw(fillColor: String) { + for shape in self.shapes { + shape.draw(fillColor: fillColor) + } + } +} +/*: +### Usage: +*/ +var whiteboard = Whiteboard(Circle(), Square()) +whiteboard.draw(fillColor: "Red") +/*: +🍧 Decorator +------------ + +The decorator pattern is used to extend or alter the functionality of objects at run- time by wrapping them in an object of a decorator class. +This provides a flexible alternative to using inheritance to modify behaviour. + +### Example +*/ +protocol CostHaving { + var cost: Double { get } +} + +protocol IngredientsHaving { + var ingredients: [String] { get } +} + +typealias BeverageDataHaving = CostHaving & IngredientsHaving + +struct SimpleCoffee: BeverageDataHaving { + let cost: Double = 1.0 + let ingredients = ["Water", "Coffee"] +} + +protocol BeverageHaving: BeverageDataHaving { + var beverage: BeverageDataHaving { get } +} + +struct Milk: BeverageHaving { + + let beverage: BeverageDataHaving + + var cost: Double { + return beverage.cost + 0.5 + } + + var ingredients: [String] { + return beverage.ingredients + ["Milk"] + } +} + +struct WhipCoffee: BeverageHaving { + + let beverage: BeverageDataHaving + + var cost: Double { + return beverage.cost + 0.5 + } + + var ingredients: [String] { + return beverage.ingredients + ["Whip"] + } +} +/*: +### Usage: +*/ +var someCoffee: BeverageDataHaving = SimpleCoffee() +print("Cost: \(someCoffee.cost); Ingredients: \(someCoffee.ingredients)") +someCoffee = Milk(beverage: someCoffee) +print("Cost: \(someCoffee.cost); Ingredients: \(someCoffee.ingredients)") +someCoffee = WhipCoffee(beverage: someCoffee) +print("Cost: \(someCoffee.cost); Ingredients: \(someCoffee.ingredients)") +/*: +🎁 Façade +--------- + +The facade pattern is used to define a simplified interface to a more complex subsystem. + +### Example +*/ +final class Defaults { + + private let defaults: UserDefaults + + init(defaults: UserDefaults = .standard) { + self.defaults = defaults + } + + subscript(key: String) -> String? { + get { + return defaults.string(forKey: key) + } + + set { + defaults.set(newValue, forKey: key) + } + } +} +/*: +### Usage +*/ +let storage = Defaults() + +// Store +storage["Bishop"] = "Disconnect me. I’d rather be nothing" + +// Read +storage["Bishop"] +/*: +## 🍃 Flyweight +The flyweight pattern is used to minimize memory usage or computational expenses by sharing as much as possible with other similar objects. +### Example +*/ +// Instances of SpecialityCoffee will be the Flyweights +struct SpecialityCoffee { + let origin: String +} + +protocol CoffeeSearching { + func search(origin: String) -> SpecialityCoffee? +} + +// Menu acts as a factory and cache for SpecialityCoffee flyweight objects +final class Menu: CoffeeSearching { + + private var coffeeAvailable: [String: SpecialityCoffee] = [:] + + func search(origin: String) -> SpecialityCoffee? { + if coffeeAvailable.index(forKey: origin) == nil { + coffeeAvailable[origin] = SpecialityCoffee(origin: origin) + } + + return coffeeAvailable[origin] + } +} + +final class CoffeeShop { + private var orders: [Int: SpecialityCoffee] = [:] + private let menu: CoffeeSearching + + init(menu: CoffeeSearching) { + self.menu = menu + } + + func takeOrder(origin: String, table: Int) { + orders[table] = menu.search(origin: origin) + } + + func serve() { + for (table, origin) in orders { + print("Serving \(origin) to table \(table)") + } + } +} +/*: +### Usage +*/ +let coffeeShop = CoffeeShop(menu: Menu()) + +coffeeShop.takeOrder(origin: "Yirgacheffe, Ethiopia", table: 1) +coffeeShop.takeOrder(origin: "Buziraguhindwa, Burundi", table: 3) + +coffeeShop.serve() +/*: +☔ Protection Proxy +------------------ + +The proxy pattern is used to provide a surrogate or placeholder object, which references an underlying object. +Protection proxy is restricting access. + +### Example +*/ +protocol DoorOpening { + func open(doors: String) -> String +} + +final class HAL9000: DoorOpening { + func open(doors: String) -> String { + return ("HAL9000: Affirmative, Dave. I read you. Opened \(doors).") + } +} + +final class CurrentComputer: DoorOpening { + private var computer: HAL9000! + + func authenticate(password: String) -> Bool { + + guard password == "pass" else { + return false + } + + computer = HAL9000() + + return true + } + + func open(doors: String) -> String { + + guard computer != nil else { + return "Access Denied. I'm afraid I can't do that." + } + + return computer.open(doors: doors) + } +} +/*: +### Usage +*/ +let computer = CurrentComputer() +let podBay = "Pod Bay Doors" + +computer.open(doors: podBay) + +computer.authenticate(password: "pass") +computer.open(doors: podBay) +/*: +🍬 Virtual Proxy +---------------- + +The proxy pattern is used to provide a surrogate or placeholder object, which references an underlying object. +Virtual proxy is used for loading object on demand. + +### Example +*/ +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() + } +} +/*: +### Usage +*/ +let humanInterface = HEVSuitHumanInterface() +humanInterface.administerMorphine() diff --git a/Design-Patterns-CN.playground/Pages/Structural.xcplaygroundpage/timeline.xctimeline b/Design-Patterns-CN.playground/Pages/Structural.xcplaygroundpage/timeline.xctimeline new file mode 100644 index 0000000..bf468af --- /dev/null +++ b/Design-Patterns-CN.playground/Pages/Structural.xcplaygroundpage/timeline.xctimeline @@ -0,0 +1,6 @@ + + + + + diff --git a/Design-Patterns-CN.playground/contents.xcplayground b/Design-Patterns-CN.playground/contents.xcplayground new file mode 100644 index 0000000..9c4add8 --- /dev/null +++ b/Design-Patterns-CN.playground/contents.xcplayground @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index 3d9dc60..d4d5a88 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,11 @@ -Design Patterns implemented in Swift 5.0 +设计模式(Swift 5.0 实现) ======================================== -A short cheat-sheet with Xcode 10.2 Playground ([Design-Patterns.playground.zip](https://raw.githubusercontent.com/ochococo/Design-Patterns-In-Swift/master/Design-Patterns.playground.zip)). +👷 源项目由 [@nsmeme](http://twitter.com/nsmeme) (Oktawian Chojnacki) 维护。 -👷 Project maintained by: [@nsmeme](http://twitter.com/nsmeme) (Oktawian Chojnacki) - -❤️ Please consider supporting my work, [become my Sponsor!](https://github.com/sponsors/ochococo) 🙏 - - -How to generate README, Playground and zip from source: [GENERATE.md](https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/GENERATE.md) +🇨🇳 中文版由 [@binglogo](https://twitter.com/binglogo) 整理翻译。 ```swift @@ -34,22 +29,22 @@ print("Welcome!") | [🏃 Visitor](#-visitor) | | | -Behavioral -========== - ->In software engineering, behavioral design patterns are design patterns that identify common communication patterns between objects and realize these patterns. By doing so, these patterns increase flexibility in carrying out this communication. -> ->**Source:** [wikipedia.org](http://en.wikipedia.org/wiki/Behavioral_pattern) + 行为型模式 + ======== + + >在软件工程中, 行为型模式为设计模式的一种类型,用来识别对象之间的常用交流模式并加以实现。如此,可在进行这些交流活动时增强弹性。 + > + >**来源:** [维基百科](https://zh.wikipedia.org/wiki/%E8%A1%8C%E7%82%BA%E5%9E%8B%E6%A8%A1%E5%BC%8F) -🐝 Chain Of Responsibility --------------------------- +🐝 责任链(Chain Of Responsibility) +------------------------------ -The chain of responsibility pattern is used to process varied requests, each of which may be dealt with by a different handler. +责任链模式在面向对象程式设计里是一种软件设计模式,它包含了一些命令对象和一系列的处理对象。每一个处理对象决定它能处理哪些命令对象,它也知道如何将它不能处理的命令对象传递给该链中的下一个处理对象。 -### Example: +### 示例: ```swift @@ -129,27 +124,28 @@ final class ATM: Withdrawing { } ``` -### Usage - + ### 用法 + ```swift -// Create piles of money and link them together 10 < 20 < 50 < 100.** +// 创建一系列的钱堆,并将其链接起来:10<20<50<100 let ten = MoneyPile(value: 10, quantity: 6, next: nil) let twenty = MoneyPile(value: 20, quantity: 2, next: ten) let fifty = MoneyPile(value: 50, quantity: 2, next: twenty) let hundred = MoneyPile(value: 100, quantity: 1, next: fifty) -// Build ATM. +// 创建 ATM 实例 var atm = ATM(hundred: hundred, fifty: fifty, twenty: twenty, ten: ten) atm.withdraw(amount: 310) // Cannot because ATM has only 300 atm.withdraw(amount: 100) // Can withdraw - 1x100 ``` -👫 Command ----------- - -The command pattern is used to express a request, including the call to be made and all of its required parameters, in a command object. The command may then be executed immediately or held for later use. - -### Example: +👫 命令(Command) + ------------ + 命令模式是一种设计模式,它尝试以对象来代表实际行动。命令对象可以把行动(action) 及其参数封装起来,于是这些行动可以被: + * 重复多次 + * 取消(如果该对象有实现的话) + * 取消后又再重做 + ### 示例: ```swift protocol DoorCommand { @@ -199,7 +195,7 @@ final class HAL9000DoorsOperations { } ``` -### Usage: +### 用法 ```swift let podBayDoors = "Pod Bay Doors" @@ -209,12 +205,12 @@ doorModule.open() doorModule.close() ``` -🎶 Interpreter --------------- +🎶 解释器(Interpreter) + ------------------ -The interpreter pattern is used to evaluate sentences in a language. + 给定一种语言,定义他的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中句子。 -### Example + ### 示例: ```swift @@ -284,7 +280,7 @@ final class AddExpression: IntegerExpression { } ``` -### Usage +### 用法 ```swift var context = IntegerContext() @@ -302,12 +298,12 @@ context.assign(expression: c, value: 3) var result = expression.evaluate(context) ``` -🍫 Iterator ------------ - -The iterator pattern is used to provide a standard interface for traversing a collection of items in an aggregate object without the need to understand its underlying structure. +🍫 迭代器(Iterator) + --------------- -### Example: + 迭代器模式可以让用户通过特定的接口巡访容器中的每一个元素而不用了解底层的实现。 + + ### 示例: ```swift struct Novella { @@ -340,7 +336,7 @@ extension Novellas: Sequence { } ``` -### Usage +### 用法 ```swift let greatNovellas = Novellas(novellas: [Novella(name: "The Mist")] ) @@ -350,12 +346,12 @@ for novella in greatNovellas { } ``` -💐 Mediator ------------ +💐 中介者(Mediator) + --------------- -The mediator pattern is used to reduce coupling between classes that communicate with each other. Instead of classes communicating directly, and thus requiring knowledge of their implementation, the classes send messages via a mediator object. + 用一个中介者对象封装一系列的对象交互,中介者使各对象不需要显示地相互作用,从而使耦合松散,而且可以独立地改变它们之间的交互。 -### Example + ### 示例: ```swift protocol Receiver { @@ -400,7 +396,7 @@ final class MessageMediator: Sender { ``` -### Usage +### 用法 ```swift func spamMonster(message: String, worker: MessageMediator) { @@ -418,18 +414,18 @@ spamMonster(message: "I'd Like to Add you to My Professional Network", worker: m ``` -💾 Memento ----------- +💾 备忘录(Memento) +-------------- -The memento pattern is used to capture the current state of an object and store it in such a manner that it can be restored at a later time without breaking the rules of encapsulation. +在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样就可以将该对象恢复到原先保存的状态 -### Example +### 示例: ```swift typealias Memento = [String: String] ``` -Originator +发起人(Originator) ```swift protocol MementoConvertible { @@ -468,7 +464,7 @@ struct GameState: MementoConvertible { } ``` -Caretaker +管理者(Caretaker) ```swift enum CheckPoint { @@ -486,7 +482,7 @@ enum CheckPoint { } ``` -### Usage +### 用法 ```swift var gameState = GameState(chapter: "Black Mesa Inbound", weapon: "Crowbar") @@ -509,13 +505,12 @@ if let memento = CheckPoint.restore(saveName: "gameState1") as? Memento { } ``` -👓 Observer ------------ +👓 观察者(Observer) +--------------- -The observer pattern is used to allow an object to publish changes to its state. -Other objects subscribe to be immediately notified of any changes. +一个目标对象管理所有相依于它的观察者对象,并且在它本身的状态改变时主动发出通知 -### Example +### 示例: ```swift protocol PropertyObserver : class { @@ -554,7 +549,7 @@ final class Observer : PropertyObserver { } ``` -### Usage +### 用法 ```swift var observerInstance = Observer() @@ -563,13 +558,13 @@ testChambers.observer = observerInstance testChambers.testChamberNumber += 1 ``` -🐉 State +🐉 状态(State) --------- -The state pattern is used to alter the behaviour of an object as its internal state changes. -The pattern allows the class for an object to apparently change at run-time. +在状态模式中,对象的行为是基于它的内部状态而改变的。 +这个模式允许某个类对象在运行时发生改变。 -### Example +### 示例: ```swift final class Context { @@ -614,7 +609,7 @@ class AuthorizedState: State { } ``` -### Usage +### 用法 ```swift let userContext = Context() @@ -625,12 +620,15 @@ userContext.changeStateToUnauthorized() (userContext.isAuthorized, userContext.userId) ``` -💡 Strategy ------------ +💡 策略(Strategy) +-------------- -The strategy pattern is used to create an interchangeable family of algorithms from which the required process is chosen at run-time. +对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。策略模式: +* 定义了一族算法(业务规则); +* 封装了每个算法; +* 这族的算法可互换代替(interchangeable)。 -### Example +### 示例: ```swift @@ -670,7 +668,7 @@ final class BladeRunner { ``` - ### Usage + ### 用法 ```swift @@ -687,12 +685,12 @@ let gaff = BladeRunner(test: GeneticTest()) let isDeckardAndroid = gaff.testIfAndroid(rachel) ``` -🏃 Visitor ----------- +🏃 访问者(Visitor) +-------------- -The visitor pattern is used to separate a relatively complex set of structured data classes from the functionality that may be performed upon the data that they hold. +封装某些作用于某种数据结构中各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。 -### Example +### 示例: ```swift protocol PlanetVisitor { @@ -733,7 +731,7 @@ final class NameVisitor: PlanetVisitor { ``` -### Usage +### 用法 ```swift let planets: [Planet] = [PlanetAlderaan(), PlanetCoruscant(), PlanetTatooine(), MoonJedha()] @@ -749,25 +747,25 @@ names ``` -Creational -========== - -> In software engineering, creational design patterns are design patterns that deal with object creation mechanisms, trying to create objects in a manner suitable to the situation. The basic form of object creation could result in design problems or added complexity to the design. Creational design patterns solve this problem by somehow controlling this object creation. -> ->**Source:** [wikipedia.org](http://en.wikipedia.org/wiki/Creational_pattern) + 创建型模式 + ======== + + > 创建型模式是处理对象创建的设计模式,试图根据实际情况使用合适的方式创建对象。基本的对象创建方式可能会导致设计上的问题,或增加设计的复杂度。创建型模式通过以某种方式控制对象的创建来解决问题。 + > + >**来源:** [维基百科](https://zh.wikipedia.org/wiki/%E5%89%B5%E5%BB%BA%E5%9E%8B%E6%A8%A1%E5%BC%8F) + -🌰 Abstract Factory -------------------- +🌰 抽象工厂(Abstract Factory) +------------- -The abstract factory pattern is used to provide a client with a set of related or dependant objects. -The "family" of objects created by the factory are determined at run-time. +抽象工厂模式提供了一种方式,可以将一组具有同一主题的单独的工厂封装起来。在正常使用中,客户端程序需要创建抽象工厂的具体实现,然后使用抽象工厂作为接口来创建这一主题的具体对象。 -### Example +### 示例: -Protocols +协议 ```swift @@ -783,7 +781,7 @@ protocol BurgerMaking { func make() -> BurgerDescribing } -// Number implementations with factory methods +// 工厂方法实现 final class BigKahunaBurger: BurgerMaking { func make() -> BurgerDescribing { @@ -799,7 +797,7 @@ final class JackInTheBox: BurgerMaking { ``` -Abstract factory +抽象工厂 ```swift @@ -819,20 +817,19 @@ enum BurgerFactoryType: BurgerMaking { } ``` -### Usage +### 用法 ```swift let bigKahuna = BurgerFactoryType.bigKahuna.make() let jackInTheBox = BurgerFactoryType.jackInTheBox.make() ``` -👷 Builder ----------- +👷 生成器(Builder) +-------------- -The builder pattern is used to create complex objects with constituent parts that must be created in the same order or using a specific algorithm. -An external class controls the construction algorithm. +一种对象构建模式。它可以将复杂对象的建造过程抽象出来(抽象类别),使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象。 -### Example +### 示例: ```swift final class DeathStarBuilder { @@ -871,7 +868,7 @@ struct DeathStar : CustomStringConvertible { } ``` -### Usage +### 用法 ```swift let empire = DeathStarBuilder { builder in @@ -883,12 +880,12 @@ let empire = DeathStarBuilder { builder in let deathStar = DeathStar(builder:empire) ``` -🏭 Factory Method ------------------ +🏭 工厂方法(Factory Method) +----------------------- -The factory pattern is used to replace class constructors, abstracting the process of object generation so that the type of the object instantiated can be determined at run-time. +定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类。工厂方法让类的实例化推迟到子类中进行。 -### Example +### 示例: ```swift protocol CurrencyDescribing { @@ -939,7 +936,7 @@ enum CurrencyFactory { } ``` -### Usage +### 用法 ```swift let noCurrencyCode = "No Currency Code Available" @@ -950,13 +947,12 @@ CurrencyFactory.currency(for: .unitedStates)?.code ?? noCurrencyCode CurrencyFactory.currency(for: .uk)?.code ?? noCurrencyCode ``` -🃏 Prototype ------------- +🃏 原型(Prototype) +-------------- -The prototype pattern is used to instantiate a new object by copying all of the properties of an existing object, creating an independent clone. -This practise is particularly useful when the construction of a new object is inefficient. +通过“复制”一个已经存在的实例来返回新的实例,而不是新建实例。被复制的实例就是我们所称的“原型”,这个原型是可定制的。 -### Example +### 示例: ```swift struct MoonWorker { @@ -974,7 +970,7 @@ struct MoonWorker { } ``` -### Usage +### 用法 ```swift let prototype = MoonWorker(name: "Sam Bell") @@ -989,14 +985,12 @@ var bell3 = prototype.clone() bell3.health = 0 ``` -💍 Singleton ------------- +💍 单例(Singleton) +-------------- -The singleton pattern ensures that only one object of a particular class is ever created. -All further references to objects of the singleton class refer to the same underlying instance. -There are very few applications, do not overuse this pattern! +单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为 -### Example: +### 示例: ```swift final class ElonMusk { @@ -1009,29 +1003,29 @@ final class ElonMusk { } ``` -### Usage: +### 用法 ```swift let elon = ElonMusk.shared // There is only one Elon Musk folks. ``` -Structural -========== +结构型模式(Structural) +==================== ->In software engineering, structural design patterns are design patterns that ease the design by identifying a simple way to realize relationships between entities. +> 在软件工程中结构型模式是设计模式,借由一以贯之的方式来了解元件间的关系,以简化设计。 > ->**Source:** [wikipedia.org](http://en.wikipedia.org/wiki/Structural_pattern) +>**来源:** [维基百科](https://zh.wikipedia.org/wiki/%E7%B5%90%E6%A7%8B%E5%9E%8B%E6%A8%A1%E5%BC%8F) -🔌 Adapter ----------- +🔌 适配器(Adapter) +-------------- -The adapter pattern is used to provide a link between two otherwise incompatible types by wrapping the "adaptee" with a class that supports the interface required by the client. +适配器模式有时候也称包装样式或者包装(wrapper)。将一个类的接口转接成用户所期待的。一个适配使得因接口不兼容而不能在一起工作的类工作在一起,做法是将类自己的接口包裹在一个已存在的类中。 -### Example +### 示例: ```swift protocol NewDeathStarSuperLaserAiming { @@ -1040,7 +1034,7 @@ protocol NewDeathStarSuperLaserAiming { } ``` -**Adaptee** +**被适配者** ```swift struct OldDeathStarSuperlaserTarget { @@ -1054,7 +1048,7 @@ struct OldDeathStarSuperlaserTarget { } ``` -**Adapter** +**适配器** ```swift struct NewDeathStarSuperlaserTarget: NewDeathStarSuperLaserAiming { @@ -1075,7 +1069,7 @@ struct NewDeathStarSuperlaserTarget: NewDeathStarSuperLaserAiming { } ``` -### Usage +### 用法 ```swift let target = OldDeathStarSuperlaserTarget(angleHorizontal: 14.0, angleVertical: 12.0) @@ -1085,12 +1079,12 @@ newFormat.angleH newFormat.angleV ``` -🌉 Bridge ----------- +🌉 桥接(Bridge) +----------- -The bridge pattern is used to separate the abstract elements of a class from the implementation details, providing the means to replace the implementation details without modifying the abstraction. +桥接模式将抽象部分与实现部分分离,使它们都可以独立的变化。 -### Example +### 示例: ```swift protocol Switch { @@ -1127,7 +1121,7 @@ final class VacuumCleaner: Appliance { } ``` -### Usage +### 用法 ```swift let tvRemoteControl = RemoteControl(appliance: TV()) @@ -1137,14 +1131,14 @@ let fancyVacuumCleanerRemoteControl = RemoteControl(appliance: VacuumCleaner()) fancyVacuumCleanerRemoteControl.turnOn() ``` -🌿 Composite -------------- +🌿 组合(Composite) +-------------- -The composite pattern is used to create hierarchical, recursive tree structures of related objects where any element of the structure may be accessed and utilised in a standard manner. +将对象组合成树形结构以表示‘部分-整体’的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。 -### Example +### 示例: -Component +组件(Component) ```swift protocol Shape { @@ -1152,7 +1146,7 @@ protocol Shape { } ``` -Leafs +叶子节点(Leafs) ```swift final class Square: Shape { @@ -1169,7 +1163,7 @@ final class Circle: Shape { ``` -Composite +组合 ```swift final class Whiteboard: Shape { @@ -1188,20 +1182,20 @@ final class Whiteboard: Shape { } ``` -### Usage: +### 用法 ```swift var whiteboard = Whiteboard(Circle(), Square()) whiteboard.draw(fillColor: "Red") ``` -🍧 Decorator ------------- +🍧 修饰(Decorator) +-------------- -The decorator pattern is used to extend or alter the functionality of objects at run- time by wrapping them in an object of a decorator class. -This provides a flexible alternative to using inheritance to modify behaviour. +修饰模式,是面向对象编程领域中,一种动态地往一个类中添加新的行为的设计模式。 +就功能而言,修饰模式相比生成子类更为灵活,这样可以给某个对象而不是整个类添加一些功能。 -### Example +### 示例: ```swift protocol CostHaving { @@ -1250,7 +1244,7 @@ struct WhipCoffee: BeverageHaving { } ``` -### Usage: +### 用法 ```swift var someCoffee: BeverageDataHaving = SimpleCoffee() @@ -1261,12 +1255,12 @@ someCoffee = WhipCoffee(beverage: someCoffee) print("Cost: \(someCoffee.cost); Ingredients: \(someCoffee.ingredients)") ``` -🎁 Façade ---------- +🎁 外观(Facade) +----------- -The facade pattern is used to define a simplified interface to a more complex subsystem. +外观模式为子系统中的一组接口提供一个统一的高层接口,使得子系统更容易使用。 -### Example +### 示例: ```swift final class Defaults { @@ -1289,7 +1283,7 @@ final class Defaults { } ``` -### Usage +### 用法 ```swift let storage = Defaults() @@ -1315,7 +1309,7 @@ protocol CoffeeSearching { func search(origin: String) -> SpecialityCoffee? } -// Menu acts as a factory and cache for SpecialityCoffee flyweight objects +// 菜单充当特制咖啡享元对象的工厂和缓存 final class Menu: CoffeeSearching { private var coffeeAvailable: [String: SpecialityCoffee] = [:] @@ -1349,7 +1343,7 @@ final class CoffeeShop { } ``` -### Usage +### 用法 ```swift let coffeeShop = CoffeeShop(menu: Menu()) @@ -1360,13 +1354,13 @@ coffeeShop.takeOrder(origin: "Buziraguhindwa, Burundi", table: 3) coffeeShop.serve() ``` -☔ Protection Proxy +☔ 保护代理模式(Protection Proxy) ------------------ -The proxy pattern is used to provide a surrogate or placeholder object, which references an underlying object. -Protection proxy is restricting access. +在代理模式中,创建一个类代表另一个底层类的功能。 +保护代理用于限制访问。 -### Example +### 示例: ```swift protocol DoorOpening { @@ -1404,7 +1398,7 @@ final class CurrentComputer: DoorOpening { } ``` -### Usage +### 用法 ```swift let computer = CurrentComputer() @@ -1416,13 +1410,13 @@ computer.authenticate(password: "pass") computer.open(doors: podBay) ``` -🍬 Virtual Proxy +🍬 虚拟代理(Virtual Proxy) ---------------- -The proxy pattern is used to provide a surrogate or placeholder object, which references an underlying object. -Virtual proxy is used for loading object on demand. +在代理模式中,创建一个类代表另一个底层类的功能。 +虚拟代理用于对象的需时加载。 -### Example +### 示例: ```swift protocol HEVSuitMedicalAid { @@ -1445,7 +1439,7 @@ final class HEVSuitHumanInterface: HEVSuitMedicalAid { } ``` -### Usage +### 用法 ```swift let humanInterface = HEVSuitHumanInterface() From d635d7956c709306bd704ce189e5ea7b07521f17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=85=B4=E5=BD=AC=5FBinboy?= Date: Fri, 13 Mar 2020 23:25:45 +0800 Subject: [PATCH 27/66] Update translation --- README.md | 39 +++++++++++++++------------- source-cn/contentsReadme.md | 26 +++++++++---------- source-cn/structural/flyweight.swift | 11 +++++--- 3 files changed, 41 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index d4d5a88..a6ee6b4 100644 --- a/README.md +++ b/README.md @@ -13,20 +13,20 @@ print("Welcome!") ``` -## Table of Contents - -| [Behavioral](#behavioral) | [Creational](#creational) | [Structural](#structural) | -| ------------------------------------------------------ | ---------------------------------------- | ---------------------------------------- | -| [🐝 Chain Of Responsibility](#-chain-of-responsibility) | [🌰 Abstract Factory](#-abstract-factory) | [🔌 Adapter](#-adapter) | -| [👫 Command](#-command) | [👷 Builder](#-builder) | [🌉 Bridge](#-bridge) | -| [🎶 Interpreter](#-interpreter) | [🏭 Factory Method](#-factory-method) | [🌿 Composite](#-composite) | -| [🍫 Iterator](#-iterator) | [🃏 Prototype](#-prototype) | [🍧 Decorator](#-decorator) | -| [💐 Mediator](#-mediator) | [💍 Singleton](#-singleton) | [🎁 Façade](#-fa-ade) | -| [💾 Memento](#-memento) | | [🍃 Flyweight](#-flyweight) | -| [👓 Observer](#-observer) | | [☔ Protection Proxy](#-protection-proxy) | -| [🐉 State](#-state) | | [🍬 Virtual Proxy](#-virtual-proxy) | -| [💡 Strategy](#-strategy) | | | -| [🏃 Visitor](#-visitor) | | | +## 目录 + +| [行为型模式](#行为型模式) | [创建型模式](#创建型模式) | [结构型模式](#结构型模式structural) | +| ------------------------------------------------------------ | --------------------------------------------------------- | ------------------------------------------------------------ | +| [🐝 责任链 Chain Of Responsibility](#-责任链chain-of-responsibility) | [🌰 抽象工厂 Abstract Factory](#-抽象工厂abstract-factory) | [🔌 适配器 Adapter](#-适配器adapter) | +| [👫 命令 Command](#-命令command) | [👷 生成器 Builder](#-生成器builder) | [🌉 桥接 Bridge](#-桥接bridge) | +| [🎶 解释器 Interpreter](#-解释器interpreter) | [🏭 工厂方法 Factory Method](#-工厂方法factory-method) | [🌿 组合 Composite](#-组合composite) | +| [🍫 迭代器 Iterator](#-迭代器iterator) | [🃏 原型 Prototype](#-原型prototype) | [🍧 修饰 Decorator](#-修饰decorator) | +| [💐 中介者 Mediator](#-中介者mediator) | [💍 单例 Singleton](#-单例singleton) | [🎁 外观 Façade](#-外观facade) | +| [💾 备忘录 Memento](#-备忘录memento) | | [🍃 享元 Flyweight](#-享元flyweight) | +| [👓 观察者 Observer](#-观察者observer) | | [☔ 保护代理 Protection Proxy](#-保护代理模式protection-proxy) | +| [🐉 状态 State](#-状态state) | | [🍬 虚拟代理 Virtual Proxy](#-虚拟代理virtual-proxy) | +| [💡 策略 Strategy](#-策略strategy) | | | +| [🏃 访问者 Visitor](#-访问者visitor) | | | 行为型模式 @@ -1295,12 +1295,15 @@ storage["Bishop"] = "Disconnect me. I’d rather be nothing" storage["Bishop"] ``` -## 🍃 Flyweight -The flyweight pattern is used to minimize memory usage or computational expenses by sharing as much as possible with other similar objects. -### Example +🍃 享元(Flyweight) +-------------- + +使用共享物件,用来尽可能减少内存使用量以及分享资讯给尽可能多的相似物件;它适合用于当大量物件只是重复因而导致无法令人接受的使用大量内存。 + +### 示例: ```swift -// Instances of SpecialityCoffee will be the Flyweights +// 特指咖啡生成的对象会是享元 struct SpecialityCoffee { let origin: String } diff --git a/source-cn/contentsReadme.md b/source-cn/contentsReadme.md index 7a92ac8..372c3ad 100644 --- a/source-cn/contentsReadme.md +++ b/source-cn/contentsReadme.md @@ -1,16 +1,16 @@ -## Table of Contents +## 目录 -| [Behavioral](#behavioral) | [Creational](#creational) | [Structural](#structural) | -| ------------------------------------------------------ | ---------------------------------------- | ---------------------------------------- | -| [🐝 Chain Of Responsibility](#-chain-of-responsibility) | [🌰 Abstract Factory](#-abstract-factory) | [🔌 Adapter](#-adapter) | -| [👫 Command](#-command) | [👷 Builder](#-builder) | [🌉 Bridge](#-bridge) | -| [🎶 Interpreter](#-interpreter) | [🏭 Factory Method](#-factory-method) | [🌿 Composite](#-composite) | -| [🍫 Iterator](#-iterator) | [🃏 Prototype](#-prototype) | [🍧 Decorator](#-decorator) | -| [💐 Mediator](#-mediator) | [💍 Singleton](#-singleton) | [🎁 Façade](#-fa-ade) | -| [💾 Memento](#-memento) | | [🍃 Flyweight](#-flyweight) | -| [👓 Observer](#-observer) | | [☔ Protection Proxy](#-protection-proxy) | -| [🐉 State](#-state) | | [🍬 Virtual Proxy](#-virtual-proxy) | -| [💡 Strategy](#-strategy) | | | -| [🏃 Visitor](#-visitor) | | | +| [行为型模式](#行为型模式) | [创建型模式](#创建型模式) | [结构型模式](#结构型模式structural) | +| ------------------------------------------------------------ | --------------------------------------------------------- | ------------------------------------------------------------ | +| [🐝 责任链 Chain Of Responsibility](#-责任链chain-of-responsibility) | [🌰 抽象工厂 Abstract Factory](#-抽象工厂abstract-factory) | [🔌 适配器 Adapter](#-适配器adapter) | +| [👫 命令 Command](#-命令command) | [👷 生成器 Builder](#-生成器builder) | [🌉 桥接 Bridge](#-桥接bridge) | +| [🎶 解释器 Interpreter](#-解释器interpreter) | [🏭 工厂方法 Factory Method](#-工厂方法factory-method) | [🌿 组合 Composite](#-组合composite) | +| [🍫 迭代器 Iterator](#-迭代器iterator) | [🃏 原型 Prototype](#-原型prototype) | [🍧 修饰 Decorator](#-修饰decorator) | +| [💐 中介者 Mediator](#-中介者mediator) | [💍 单例 Singleton](#-单例singleton) | [🎁 外观 Façade](#-外观facade) | +| [💾 备忘录 Memento](#-备忘录memento) | | [🍃 享元 Flyweight](#-享元flyweight) | +| [👓 观察者 Observer](#-观察者observer) | | [☔ 保护代理 Protection Proxy](#-保护代理模式protection-proxy) | +| [🐉 状态 State](#-状态state) | | [🍬 虚拟代理 Virtual Proxy](#-虚拟代理virtual-proxy) | +| [💡 策略 Strategy](#-策略strategy) | | | +| [🏃 访问者 Visitor](#-访问者visitor) | | | diff --git a/source-cn/structural/flyweight.swift b/source-cn/structural/flyweight.swift index fe90a60..97ac692 100644 --- a/source-cn/structural/flyweight.swift +++ b/source-cn/structural/flyweight.swift @@ -1,9 +1,12 @@ /*: -## 🍃 Flyweight -The flyweight pattern is used to minimize memory usage or computational expenses by sharing as much as possible with other similar objects. -### Example +🍃 享元(Flyweight) +-------------- + +使用共享物件,用来尽可能减少内存使用量以及分享资讯给尽可能多的相似物件;它适合用于当大量物件只是重复因而导致无法令人接受的使用大量内存。 + +### 示例: */ -// Instances of SpecialityCoffee will be the Flyweights +// 特指咖啡生成的对象会是享元 struct SpecialityCoffee { let origin: String } From f3dd3279871e3579a1139c69ba409a804a5d1a8d Mon Sep 17 00:00:00 2001 From: Oktawian Chojnacki Date: Tue, 17 Mar 2020 20:17:46 +0100 Subject: [PATCH 28/66] Rebase `chinese` from `BinBoy` and link to `README-CN.md`. --- Design-Patterns-CN.playground.zip | Bin 24340 -> 25756 bytes .../Contents.swift | 146 +- .../Contents.swift | 86 +- .../Index.xcplaygroundpage/Contents.swift | 21 +- .../Contents.swift | 114 +- Design-Patterns.playground.zip | Bin 159940 -> 160032 bytes .../Index.xcplaygroundpage/Contents.swift | 6 +- README-CN.md | 1458 +++++++++++++++++ README.md | 350 ++-- generate-playground-cn.sh | 10 +- source-cn/Index/header.md | 4 +- source-cn/Index/welcome.swift | 2 +- source/Index/header.md | 6 +- 13 files changed, 1836 insertions(+), 367 deletions(-) create mode 100644 README-CN.md diff --git a/Design-Patterns-CN.playground.zip b/Design-Patterns-CN.playground.zip index 01877beb2f74f678df7c2e3438a23fd9c450d25e..628cc5603c913284c4215105e0bb435f57262610 100644 GIT binary patch delta 11814 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 LfdTaXnf?C&w?$js delta 10227 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 jD-Fi5M*FYke^HYERdew#Q1V}f0*In software engineering, behavioral design patterns are design patterns that identify common communication patterns between objects and realize these patterns. By doing so, these patterns increase flexibility in carrying out this communication. -> ->**Source:** [wikipedia.org](http://en.wikipedia.org/wiki/Behavioral_pattern) - -## Table of Contents - -* [Behavioral](Behavioral) -* [Creational](Creational) -* [Structural](Structural) - + 行为型模式 + ======== + + >在软件工程中, 行为型模式为设计模式的一种类型,用来识别对象之间的常用交流模式并加以实现。如此,可在进行这些交流活动时增强弹性。 + > + >**来源:** [维基百科](https://zh.wikipedia.org/wiki/%E8%A1%8C%E7%82%BA%E5%9E%8B%E6%A8%A1%E5%BC%8F) + +## 目录 + +* [行为型模式](Behavioral) +* [创建型模式](Creational) +* [结构型模式](Structural) */ import Foundation /*: -🐝 Chain Of Responsibility --------------------------- +🐝 责任链(Chain Of Responsibility) +------------------------------ -The chain of responsibility pattern is used to process varied requests, each of which may be dealt with by a different handler. +责任链模式在面向对象程式设计里是一种软件设计模式,它包含了一些命令对象和一系列的处理对象。每一个处理对象决定它能处理哪些命令对象,它也知道如何将它不能处理的命令对象传递给该链中的下一个处理对象。 -### Example: +### 示例: */ protocol Withdrawing { @@ -99,25 +98,26 @@ final class ATM: Withdrawing { } } /*: -### Usage -*/ -// Create piles of money and link them together 10 < 20 < 50 < 100.** + ### 用法 + */ +// 创建一系列的钱堆,并将其链接起来:10<20<50<100 let ten = MoneyPile(value: 10, quantity: 6, next: nil) let twenty = MoneyPile(value: 20, quantity: 2, next: ten) let fifty = MoneyPile(value: 50, quantity: 2, next: twenty) let hundred = MoneyPile(value: 100, quantity: 1, next: fifty) -// Build ATM. +// 创建 ATM 实例 var atm = ATM(hundred: hundred, fifty: fifty, twenty: twenty, ten: ten) atm.withdraw(amount: 310) // Cannot because ATM has only 300 atm.withdraw(amount: 100) // Can withdraw - 1x100 /*: -👫 Command ----------- - -The command pattern is used to express a request, including the call to be made and all of its required parameters, in a command object. The command may then be executed immediately or held for later use. - -### Example: +👫 命令(Command) + ------------ + 命令模式是一种设计模式,它尝试以对象来代表实际行动。命令对象可以把行动(action) 及其参数封装起来,于是这些行动可以被: + * 重复多次 + * 取消(如果该对象有实现的话) + * 取消后又再重做 + ### 示例: */ protocol DoorCommand { func execute() -> String @@ -165,7 +165,7 @@ final class HAL9000DoorsOperations { } } /*: -### Usage: +### 用法 */ let podBayDoors = "Pod Bay Doors" let doorModule = HAL9000DoorsOperations(doors:podBayDoors) @@ -173,12 +173,12 @@ let doorModule = HAL9000DoorsOperations(doors:podBayDoors) doorModule.open() doorModule.close() /*: -🎶 Interpreter --------------- +🎶 解释器(Interpreter) + ------------------ -The interpreter pattern is used to evaluate sentences in a language. + 给定一种语言,定义他的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中句子。 -### Example + ### 示例: */ protocol IntegerExpression { @@ -246,7 +246,7 @@ final class AddExpression: IntegerExpression { } } /*: -### Usage +### 用法 */ var context = IntegerContext() @@ -262,12 +262,12 @@ context.assign(expression: c, value: 3) var result = expression.evaluate(context) /*: -🍫 Iterator ------------ - -The iterator pattern is used to provide a standard interface for traversing a collection of items in an aggregate object without the need to understand its underlying structure. +🍫 迭代器(Iterator) + --------------- -### Example: + 迭代器模式可以让用户通过特定的接口巡访容器中的每一个元素而不用了解底层的实现。 + + ### 示例: */ struct Novella { let name: String @@ -298,7 +298,7 @@ extension Novellas: Sequence { } } /*: -### Usage +### 用法 */ let greatNovellas = Novellas(novellas: [Novella(name: "The Mist")] ) @@ -306,12 +306,12 @@ for novella in greatNovellas { print("I've read: \(novella)") } /*: -💐 Mediator ------------ +💐 中介者(Mediator) + --------------- -The mediator pattern is used to reduce coupling between classes that communicate with each other. Instead of classes communicating directly, and thus requiring knowledge of their implementation, the classes send messages via a mediator object. + 用一个中介者对象封装一系列的对象交互,中介者使各对象不需要显示地相互作用,从而使耦合松散,而且可以独立地改变它们之间的交互。 -### Example + ### 示例: */ protocol Receiver { associatedtype MessageType @@ -354,7 +354,7 @@ final class MessageMediator: Sender { } /*: -### Usage +### 用法 */ func spamMonster(message: String, worker: MessageMediator) { worker.send(message: message) @@ -370,16 +370,16 @@ messagesMediator.add(recipient: user1) spamMonster(message: "I'd Like to Add you to My Professional Network", worker: messagesMediator) /*: -💾 Memento ----------- +💾 备忘录(Memento) +-------------- -The memento pattern is used to capture the current state of an object and store it in such a manner that it can be restored at a later time without breaking the rules of encapsulation. +在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样就可以将该对象恢复到原先保存的状态 -### Example +### 示例: */ typealias Memento = [String: String] /*: -Originator +发起人(Originator) */ protocol MementoConvertible { var memento: Memento { get } @@ -416,7 +416,7 @@ struct GameState: MementoConvertible { } } /*: -Caretaker +管理者(Caretaker) */ enum CheckPoint { @@ -432,7 +432,7 @@ enum CheckPoint { } } /*: -### Usage +### 用法 */ var gameState = GameState(chapter: "Black Mesa Inbound", weapon: "Crowbar") @@ -453,13 +453,12 @@ if let memento = CheckPoint.restore(saveName: "gameState1") as? Memento { dump(finalState) } /*: -👓 Observer ------------ +👓 观察者(Observer) +--------------- -The observer pattern is used to allow an object to publish changes to its state. -Other objects subscribe to be immediately notified of any changes. +一个目标对象管理所有相依于它的观察者对象,并且在它本身的状态改变时主动发出通知 -### Example +### 示例: */ protocol PropertyObserver : class { func willChange(propertyName: String, newPropertyValue: Any?) @@ -496,20 +495,20 @@ final class Observer : PropertyObserver { } } /*: -### Usage +### 用法 */ var observerInstance = Observer() var testChambers = TestChambers() testChambers.observer = observerInstance testChambers.testChamberNumber += 1 /*: -🐉 State +🐉 状态(State) --------- -The state pattern is used to alter the behaviour of an object as its internal state changes. -The pattern allows the class for an object to apparently change at run-time. +在状态模式中,对象的行为是基于它的内部状态而改变的。 +这个模式允许某个类对象在运行时发生改变。 -### Example +### 示例: */ final class Context { private var state: State = UnauthorizedState() @@ -552,7 +551,7 @@ class AuthorizedState: State { func userId(context: Context) -> String? { return userId } } /*: -### Usage +### 用法 */ let userContext = Context() (userContext.isAuthorized, userContext.userId) @@ -561,12 +560,15 @@ userContext.changeStateToAuthorized(userId: "admin") userContext.changeStateToUnauthorized() (userContext.isAuthorized, userContext.userId) /*: -💡 Strategy ------------ +💡 策略(Strategy) +-------------- -The strategy pattern is used to create an interchangeable family of algorithms from which the required process is chosen at run-time. +对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。策略模式: +* 定义了一族算法(业务规则); +* 封装了每个算法; +* 这族的算法可互换代替(interchangeable)。 -### Example +### 示例: */ struct TestSubject { @@ -604,7 +606,7 @@ final class BladeRunner { } /*: - ### Usage + ### 用法 */ let rachel = TestSubject(pupilDiameter: 30.2, @@ -619,12 +621,12 @@ let isRachelAndroid = deckard.testIfAndroid(rachel) let gaff = BladeRunner(test: GeneticTest()) let isDeckardAndroid = gaff.testIfAndroid(rachel) /*: -🏃 Visitor ----------- +🏃 访问者(Visitor) +-------------- -The visitor pattern is used to separate a relatively complex set of structured data classes from the functionality that may be performed upon the data that they hold. +封装某些作用于某种数据结构中各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。 -### Example +### 示例: */ protocol PlanetVisitor { func visit(planet: PlanetAlderaan) @@ -663,7 +665,7 @@ final class NameVisitor: PlanetVisitor { } /*: -### Usage +### 用法 */ let planets: [Planet] = [PlanetAlderaan(), PlanetCoruscant(), PlanetTatooine(), MoonJedha()] diff --git a/Design-Patterns-CN.playground/Pages/Creational.xcplaygroundpage/Contents.swift b/Design-Patterns-CN.playground/Pages/Creational.xcplaygroundpage/Contents.swift index 6b46311..bb454a1 100644 --- a/Design-Patterns-CN.playground/Pages/Creational.xcplaygroundpage/Contents.swift +++ b/Design-Patterns-CN.playground/Pages/Creational.xcplaygroundpage/Contents.swift @@ -1,30 +1,28 @@ /*: -Creational -========== - -> In software engineering, creational design patterns are design patterns that deal with object creation mechanisms, trying to create objects in a manner suitable to the situation. The basic form of object creation could result in design problems or added complexity to the design. Creational design patterns solve this problem by somehow controlling this object creation. -> ->**Source:** [wikipedia.org](http://en.wikipedia.org/wiki/Creational_pattern) - -## Table of Contents - -* [Behavioral](Behavioral) -* [Creational](Creational) -* [Structural](Structural) - + 创建型模式 + ======== + + > 创建型模式是处理对象创建的设计模式,试图根据实际情况使用合适的方式创建对象。基本的对象创建方式可能会导致设计上的问题,或增加设计的复杂度。创建型模式通过以某种方式控制对象的创建来解决问题。 + > + >**来源:** [维基百科](https://zh.wikipedia.org/wiki/%E5%89%B5%E5%BB%BA%E5%9E%8B%E6%A8%A1%E5%BC%8F) + +## 目录 + +* [行为型模式](Behavioral) +* [创建型模式](Creational) +* [结构型模式](Structural) */ import Foundation /*: -🌰 Abstract Factory -------------------- +🌰 抽象工厂(Abstract Factory) +------------- -The abstract factory pattern is used to provide a client with a set of related or dependant objects. -The "family" of objects created by the factory are determined at run-time. +抽象工厂模式提供了一种方式,可以将一组具有同一主题的单独的工厂封装起来。在正常使用中,客户端程序需要创建抽象工厂的具体实现,然后使用抽象工厂作为接口来创建这一主题的具体对象。 -### Example +### 示例: -Protocols +协议 */ protocol BurgerDescribing { @@ -39,7 +37,7 @@ protocol BurgerMaking { func make() -> BurgerDescribing } -// Number implementations with factory methods +// 工厂方法实现 final class BigKahunaBurger: BurgerMaking { func make() -> BurgerDescribing { @@ -54,7 +52,7 @@ final class JackInTheBox: BurgerMaking { } /*: -Abstract factory +抽象工厂 */ enum BurgerFactoryType: BurgerMaking { @@ -72,18 +70,17 @@ enum BurgerFactoryType: BurgerMaking { } } /*: -### Usage +### 用法 */ let bigKahuna = BurgerFactoryType.bigKahuna.make() let jackInTheBox = BurgerFactoryType.jackInTheBox.make() /*: -👷 Builder ----------- +👷 生成器(Builder) +-------------- -The builder pattern is used to create complex objects with constituent parts that must be created in the same order or using a specific algorithm. -An external class controls the construction algorithm. +一种对象构建模式。它可以将复杂对象的建造过程抽象出来(抽象类别),使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象。 -### Example +### 示例: */ final class DeathStarBuilder { @@ -120,7 +117,7 @@ struct DeathStar : CustomStringConvertible { } } /*: -### Usage +### 用法 */ let empire = DeathStarBuilder { builder in builder.x = 0.1 @@ -130,12 +127,12 @@ let empire = DeathStarBuilder { builder in let deathStar = DeathStar(builder:empire) /*: -🏭 Factory Method ------------------ +🏭 工厂方法(Factory Method) +----------------------- -The factory pattern is used to replace class constructors, abstracting the process of object generation so that the type of the object instantiated can be determined at run-time. +定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类。工厂方法让类的实例化推迟到子类中进行。 -### Example +### 示例: */ protocol CurrencyDescribing { var symbol: String { get } @@ -184,7 +181,7 @@ enum CurrencyFactory { } } /*: -### Usage +### 用法 */ let noCurrencyCode = "No Currency Code Available" @@ -193,13 +190,12 @@ CurrencyFactory.currency(for: .spain)?.code ?? noCurrencyCode CurrencyFactory.currency(for: .unitedStates)?.code ?? noCurrencyCode CurrencyFactory.currency(for: .uk)?.code ?? noCurrencyCode /*: -🃏 Prototype ------------- +🃏 原型(Prototype) +-------------- -The prototype pattern is used to instantiate a new object by copying all of the properties of an existing object, creating an independent clone. -This practise is particularly useful when the construction of a new object is inefficient. +通过“复制”一个已经存在的实例来返回新的实例,而不是新建实例。被复制的实例就是我们所称的“原型”,这个原型是可定制的。 -### Example +### 示例: */ struct MoonWorker { @@ -215,7 +211,7 @@ struct MoonWorker { } } /*: -### Usage +### 用法 */ let prototype = MoonWorker(name: "Sam Bell") @@ -228,14 +224,12 @@ bell2.health = 23 var bell3 = prototype.clone() bell3.health = 0 /*: -💍 Singleton ------------- +💍 单例(Singleton) +-------------- -The singleton pattern ensures that only one object of a particular class is ever created. -All further references to objects of the singleton class refer to the same underlying instance. -There are very few applications, do not overuse this pattern! +单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为 -### Example: +### 示例: */ final class ElonMusk { @@ -246,6 +240,6 @@ final class ElonMusk { } } /*: -### Usage: +### 用法 */ let elon = ElonMusk.shared // There is only one Elon Musk folks. diff --git a/Design-Patterns-CN.playground/Pages/Index.xcplaygroundpage/Contents.swift b/Design-Patterns-CN.playground/Pages/Index.xcplaygroundpage/Contents.swift index 4a54f9f..10d89a8 100644 --- a/Design-Patterns-CN.playground/Pages/Index.xcplaygroundpage/Contents.swift +++ b/Design-Patterns-CN.playground/Pages/Index.xcplaygroundpage/Contents.swift @@ -1,21 +1,20 @@ /*: -Design Patterns implemented in Swift 5.0 -======================================== +设计模式(Swift 5.0 实现) +====================== -A short cheat-sheet with Xcode 10.2 Playground ([Design-Patterns.playground.zip](https://raw.githubusercontent.com/ochococo/Design-Patterns-In-Swift/master/Design-Patterns.playground.zip)). +([Design-Patterns-CN.playground.zip](https://raw.githubusercontent.com/ochococo/Design-Patterns-In-Swift/master/Design-Patterns-CN.playground.zip)). -👷 Project maintained by: [@nsmeme](http://twitter.com/nsmeme) (Oktawian Chojnacki) +👷 源项目由 [@nsmeme](http://twitter.com/nsmeme) (Oktawian Chojnacki) 维护。 -🚀 How to generate README, Playground and zip from source: [GENERATE.md](https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/GENERATE.md) +🇨🇳 中文版由 [@binglogo](https://twitter.com/binglogo) 整理翻译。 -## Table of Contents - -* [Behavioral](Behavioral) -* [Creational](Creational) -* [Structural](Structural) +## 目录 +* [行为型模式](Behavioral) +* [创建型模式](Creational) +* [结构型模式](Structural) */ import Foundation -print("Welcome!") +print("您好!") diff --git a/Design-Patterns-CN.playground/Pages/Structural.xcplaygroundpage/Contents.swift b/Design-Patterns-CN.playground/Pages/Structural.xcplaygroundpage/Contents.swift index 29c0ef1..0ee03d7 100644 --- a/Design-Patterns-CN.playground/Pages/Structural.xcplaygroundpage/Contents.swift +++ b/Design-Patterns-CN.playground/Pages/Structural.xcplaygroundpage/Contents.swift @@ -1,34 +1,33 @@ /*: -Structural -========== +结构型模式(Structural) +==================== ->In software engineering, structural design patterns are design patterns that ease the design by identifying a simple way to realize relationships between entities. +> 在软件工程中结构型模式是设计模式,借由一以贯之的方式来了解元件间的关系,以简化设计。 > ->**Source:** [wikipedia.org](http://en.wikipedia.org/wiki/Structural_pattern) +>**来源:** [维基百科](https://zh.wikipedia.org/wiki/%E7%B5%90%E6%A7%8B%E5%9E%8B%E6%A8%A1%E5%BC%8F) -## Table of Contents - -* [Behavioral](Behavioral) -* [Creational](Creational) -* [Structural](Structural) +## 目录 +* [行为型模式](Behavioral) +* [创建型模式](Creational) +* [结构型模式](Structural) */ import Foundation /*: -🔌 Adapter ----------- +🔌 适配器(Adapter) +-------------- -The adapter pattern is used to provide a link between two otherwise incompatible types by wrapping the "adaptee" with a class that supports the interface required by the client. +适配器模式有时候也称包装样式或者包装(wrapper)。将一个类的接口转接成用户所期待的。一个适配使得因接口不兼容而不能在一起工作的类工作在一起,做法是将类自己的接口包裹在一个已存在的类中。 -### Example +### 示例: */ protocol NewDeathStarSuperLaserAiming { var angleV: Double { get } var angleH: Double { get } } /*: -**Adaptee** +**被适配者** */ struct OldDeathStarSuperlaserTarget { let angleHorizontal: Float @@ -40,7 +39,7 @@ struct OldDeathStarSuperlaserTarget { } } /*: -**Adapter** +**适配器** */ struct NewDeathStarSuperlaserTarget: NewDeathStarSuperLaserAiming { @@ -59,7 +58,7 @@ struct NewDeathStarSuperlaserTarget: NewDeathStarSuperLaserAiming { } } /*: -### Usage +### 用法 */ let target = OldDeathStarSuperlaserTarget(angleHorizontal: 14.0, angleVertical: 12.0) let newFormat = NewDeathStarSuperlaserTarget(target) @@ -67,12 +66,12 @@ let newFormat = NewDeathStarSuperlaserTarget(target) newFormat.angleH newFormat.angleV /*: -🌉 Bridge ----------- +🌉 桥接(Bridge) +----------- -The bridge pattern is used to separate the abstract elements of a class from the implementation details, providing the means to replace the implementation details without modifying the abstraction. +桥接模式将抽象部分与实现部分分离,使它们都可以独立的变化。 -### Example +### 示例: */ protocol Switch { var appliance: Appliance { get set } @@ -107,7 +106,7 @@ final class VacuumCleaner: Appliance { } } /*: -### Usage +### 用法 */ let tvRemoteControl = RemoteControl(appliance: TV()) tvRemoteControl.turnOn() @@ -115,20 +114,20 @@ tvRemoteControl.turnOn() let fancyVacuumCleanerRemoteControl = RemoteControl(appliance: VacuumCleaner()) fancyVacuumCleanerRemoteControl.turnOn() /*: -🌿 Composite -------------- +🌿 组合(Composite) +-------------- -The composite pattern is used to create hierarchical, recursive tree structures of related objects where any element of the structure may be accessed and utilised in a standard manner. +将对象组合成树形结构以表示‘部分-整体’的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。 -### Example +### 示例: -Component +组件(Component) */ protocol Shape { func draw(fillColor: String) } /*: -Leafs +叶子节点(Leafs) */ final class Square: Shape { func draw(fillColor: String) { @@ -143,7 +142,7 @@ final class Circle: Shape { } /*: -Composite +组合 */ final class Whiteboard: Shape { @@ -160,18 +159,18 @@ final class Whiteboard: Shape { } } /*: -### Usage: +### 用法 */ var whiteboard = Whiteboard(Circle(), Square()) whiteboard.draw(fillColor: "Red") /*: -🍧 Decorator ------------- +🍧 修饰(Decorator) +-------------- -The decorator pattern is used to extend or alter the functionality of objects at run- time by wrapping them in an object of a decorator class. -This provides a flexible alternative to using inheritance to modify behaviour. +修饰模式,是面向对象编程领域中,一种动态地往一个类中添加新的行为的设计模式。 +就功能而言,修饰模式相比生成子类更为灵活,这样可以给某个对象而不是整个类添加一些功能。 -### Example +### 示例: */ protocol CostHaving { var cost: Double { get } @@ -218,7 +217,7 @@ struct WhipCoffee: BeverageHaving { } } /*: -### Usage: +### 用法 */ var someCoffee: BeverageDataHaving = SimpleCoffee() print("Cost: \(someCoffee.cost); Ingredients: \(someCoffee.ingredients)") @@ -227,12 +226,12 @@ print("Cost: \(someCoffee.cost); Ingredients: \(someCoffee.ingredients)") someCoffee = WhipCoffee(beverage: someCoffee) print("Cost: \(someCoffee.cost); Ingredients: \(someCoffee.ingredients)") /*: -🎁 Façade ---------- +🎁 外观(Facade) +----------- -The facade pattern is used to define a simplified interface to a more complex subsystem. +外观模式为子系统中的一组接口提供一个统一的高层接口,使得子系统更容易使用。 -### Example +### 示例: */ final class Defaults { @@ -253,7 +252,7 @@ final class Defaults { } } /*: -### Usage +### 用法 */ let storage = Defaults() @@ -263,11 +262,14 @@ storage["Bishop"] = "Disconnect me. I’d rather be nothing" // Read storage["Bishop"] /*: -## 🍃 Flyweight -The flyweight pattern is used to minimize memory usage or computational expenses by sharing as much as possible with other similar objects. -### Example +🍃 享元(Flyweight) +-------------- + +使用共享物件,用来尽可能减少内存使用量以及分享资讯给尽可能多的相似物件;它适合用于当大量物件只是重复因而导致无法令人接受的使用大量内存。 + +### 示例: */ -// Instances of SpecialityCoffee will be the Flyweights +// 特指咖啡生成的对象会是享元 struct SpecialityCoffee { let origin: String } @@ -276,7 +278,7 @@ protocol CoffeeSearching { func search(origin: String) -> SpecialityCoffee? } -// Menu acts as a factory and cache for SpecialityCoffee flyweight objects +// 菜单充当特制咖啡享元对象的工厂和缓存 final class Menu: CoffeeSearching { private var coffeeAvailable: [String: SpecialityCoffee] = [:] @@ -309,7 +311,7 @@ final class CoffeeShop { } } /*: -### Usage +### 用法 */ let coffeeShop = CoffeeShop(menu: Menu()) @@ -318,13 +320,13 @@ coffeeShop.takeOrder(origin: "Buziraguhindwa, Burundi", table: 3) coffeeShop.serve() /*: -☔ Protection Proxy +☔ 保护代理模式(Protection Proxy) ------------------ -The proxy pattern is used to provide a surrogate or placeholder object, which references an underlying object. -Protection proxy is restricting access. +在代理模式中,创建一个类代表另一个底层类的功能。 +保护代理用于限制访问。 -### Example +### 示例: */ protocol DoorOpening { func open(doors: String) -> String @@ -360,7 +362,7 @@ final class CurrentComputer: DoorOpening { } } /*: -### Usage +### 用法 */ let computer = CurrentComputer() let podBay = "Pod Bay Doors" @@ -370,13 +372,13 @@ computer.open(doors: podBay) computer.authenticate(password: "pass") computer.open(doors: podBay) /*: -🍬 Virtual Proxy +🍬 虚拟代理(Virtual Proxy) ---------------- -The proxy pattern is used to provide a surrogate or placeholder object, which references an underlying object. -Virtual proxy is used for loading object on demand. +在代理模式中,创建一个类代表另一个底层类的功能。 +虚拟代理用于对象的需时加载。 -### Example +### 示例: */ protocol HEVSuitMedicalAid { func administerMorphine() -> String @@ -397,7 +399,7 @@ final class HEVSuitHumanInterface: HEVSuitMedicalAid { } } /*: -### Usage +### 用法 */ let humanInterface = HEVSuitHumanInterface() humanInterface.administerMorphine() diff --git a/Design-Patterns.playground.zip b/Design-Patterns.playground.zip index ec7eebe29e14dff586d70a44e13c57ebeace4339..583db0c50ee80b84a4e0fec97b0e852dd89145dd 100644 GIT binary patch delta 872 zcmX@|kaNK!PQCzdW)?065XjDS^q+3v}XCRurOfy>t;s7 z>H7;9Wu`Y2Fmi##w)YhuQ-V8Kfk=9O#fukB&~`_ftc+d&mY{ig|&5Q`^h&sM!819X=-g% zTDB2;x4PO^ygb;=?&{*`c!YoPyQ(+tA5;~6ZwB+LNme{L{^#EwbKx)SEo%yulQ@&J zbgy4(IPqypdQ6lZt77725o2!iKcPjRC-Eyf8+2Y0i#W9MYrW5*ovlGPSmcaNpBCg^ z-Ou-U%DbacqD5TimVA7$RqoFpnJ@FZYHoY3IeS)t!$kM5L}%9ugBashwWVKYo?<#G zbo2x7v=w`PUs|oqB5C>~T{3=BQSAH)aqHP9Z@zrEe23ltf8P@S{VMqQsPg%u!UE5m z8li!!Yt3W$&D)|Enn!)#T))!$#Lbr~r*EEaUETlRAAel`=ji$;P5#|Vp*2l2yw|OKxNkxo&Dy>ij%V&?oDVZnIo|($cR<)=OyOVC&kTQx_fBLJ~_Xz?t)gI@X~*O zD}Qlw`Z&vlrXzz8Czm@9W z-H^{?{&!`qZtby^ldfOg+p{|F(!ZXdt>T9+zF?nb#4gvH^i^IUz?+dtjv0}Lrk4sZ zxq>5d`#u4tCBcw5O-o_&W(G$7^x8xw>FMWFn0z78s*uX`86j?%1{L4ll*Z)Ggphcj r0n^}+$y5q4@^>1O)b`7nOqpyDqZ|sDlF(Dgh61K6HckO1VEP6CF4#7; diff --git a/Design-Patterns.playground/Pages/Index.xcplaygroundpage/Contents.swift b/Design-Patterns.playground/Pages/Index.xcplaygroundpage/Contents.swift index 4a54f9f..75f7a52 100644 --- a/Design-Patterns.playground/Pages/Index.xcplaygroundpage/Contents.swift +++ b/Design-Patterns.playground/Pages/Index.xcplaygroundpage/Contents.swift @@ -5,7 +5,11 @@ Design Patterns implemented in Swift 5.0 A short cheat-sheet with Xcode 10.2 Playground ([Design-Patterns.playground.zip](https://raw.githubusercontent.com/ochococo/Design-Patterns-In-Swift/master/Design-Patterns.playground.zip)). -👷 Project maintained by: [@nsmeme](http://twitter.com/nsmeme) (Oktawian Chojnacki) +### [🇨🇳中文版](https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/GENERATE-CN.md) + +👷 Project started by: [@nsmeme](http://twitter.com/nsmeme) (Oktawian Chojnacki) + +👷 中文版由 [@binglogo](https://twitter.com/binglogo) (棒棒彬) 整理翻译。 🚀 How to generate README, Playground and zip from source: [GENERATE.md](https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/GENERATE.md) diff --git a/README-CN.md b/README-CN.md new file mode 100644 index 0000000..ec2c8a3 --- /dev/null +++ b/README-CN.md @@ -0,0 +1,1458 @@ + + +设计模式(Swift 5.0 实现) +====================== + +([Design-Patterns-CN.playground.zip](https://raw.githubusercontent.com/ochococo/Design-Patterns-In-Swift/master/Design-Patterns-CN.playground.zip)). + +👷 源项目由 [@nsmeme](http://twitter.com/nsmeme) (Oktawian Chojnacki) 维护。 + +🇨🇳 中文版由 [@binglogo](https://twitter.com/binglogo) 整理翻译。 + + +```swift +print("您好!") +``` + + +## 目录 + +| [行为型模式](#行为型模式) | [创建型模式](#创建型模式) | [结构型模式](#结构型模式structural) | +| ------------------------------------------------------------ | --------------------------------------------------------- | ------------------------------------------------------------ | +| [🐝 责任链 Chain Of Responsibility](#-责任链chain-of-responsibility) | [🌰 抽象工厂 Abstract Factory](#-抽象工厂abstract-factory) | [🔌 适配器 Adapter](#-适配器adapter) | +| [👫 命令 Command](#-命令command) | [👷 生成器 Builder](#-生成器builder) | [🌉 桥接 Bridge](#-桥接bridge) | +| [🎶 解释器 Interpreter](#-解释器interpreter) | [🏭 工厂方法 Factory Method](#-工厂方法factory-method) | [🌿 组合 Composite](#-组合composite) | +| [🍫 迭代器 Iterator](#-迭代器iterator) | [🃏 原型 Prototype](#-原型prototype) | [🍧 修饰 Decorator](#-修饰decorator) | +| [💐 中介者 Mediator](#-中介者mediator) | [💍 单例 Singleton](#-单例singleton) | [🎁 外观 Façade](#-外观facade) | +| [💾 备忘录 Memento](#-备忘录memento) | | [🍃 享元 Flyweight](#-享元flyweight) | +| [👓 观察者 Observer](#-观察者observer) | | [☔ 保护代理 Protection Proxy](#-保护代理模式protection-proxy) | +| [🐉 状态 State](#-状态state) | | [🍬 虚拟代理 Virtual Proxy](#-虚拟代理virtual-proxy) | +| [💡 策略 Strategy](#-策略strategy) | | | +| [🏃 访问者 Visitor](#-访问者visitor) | | | + + + 行为型模式 + ======== + + >在软件工程中, 行为型模式为设计模式的一种类型,用来识别对象之间的常用交流模式并加以实现。如此,可在进行这些交流活动时增强弹性。 + > + >**来源:** [维基百科](https://zh.wikipedia.org/wiki/%E8%A1%8C%E7%82%BA%E5%9E%8B%E6%A8%A1%E5%BC%8F) + + + + +🐝 责任链(Chain Of Responsibility) +------------------------------ + +责任链模式在面向对象程式设计里是一种软件设计模式,它包含了一些命令对象和一系列的处理对象。每一个处理对象决定它能处理哪些命令对象,它也知道如何将它不能处理的命令对象传递给该链中的下一个处理对象。 + +### 示例: + +```swift + +protocol Withdrawing { + func withdraw(amount: Int) -> Bool +} + +final class MoneyPile: Withdrawing { + + let value: Int + var quantity: Int + var next: Withdrawing? + + init(value: Int, quantity: Int, next: Withdrawing?) { + self.value = value + self.quantity = quantity + self.next = next + } + + func withdraw(amount: Int) -> Bool { + + var amount = amount + + func canTakeSomeBill(want: Int) -> Bool { + return (want / self.value) > 0 + } + + var quantity = self.quantity + + while canTakeSomeBill(want: amount) { + + if quantity == 0 { + break + } + + amount -= self.value + quantity -= 1 + } + + guard amount > 0 else { + return true + } + + if let next = self.next { + return next.withdraw(amount: amount) + } + + return false + } +} + +final class ATM: Withdrawing { + + private var hundred: Withdrawing + private var fifty: Withdrawing + private var twenty: Withdrawing + private var ten: Withdrawing + + private var startPile: Withdrawing { + return self.hundred + } + + init(hundred: Withdrawing, + fifty: Withdrawing, + twenty: Withdrawing, + ten: Withdrawing) { + + self.hundred = hundred + self.fifty = fifty + self.twenty = twenty + self.ten = ten + } + + func withdraw(amount: Int) -> Bool { + return startPile.withdraw(amount: amount) + } +} +``` + + ### 用法 + +```swift +// 创建一系列的钱堆,并将其链接起来:10<20<50<100 +let ten = MoneyPile(value: 10, quantity: 6, next: nil) +let twenty = MoneyPile(value: 20, quantity: 2, next: ten) +let fifty = MoneyPile(value: 50, quantity: 2, next: twenty) +let hundred = MoneyPile(value: 100, quantity: 1, next: fifty) + +// 创建 ATM 实例 +var atm = ATM(hundred: hundred, fifty: fifty, twenty: twenty, ten: ten) +atm.withdraw(amount: 310) // Cannot because ATM has only 300 +atm.withdraw(amount: 100) // Can withdraw - 1x100 +``` + +👫 命令(Command) + ------------ + 命令模式是一种设计模式,它尝试以对象来代表实际行动。命令对象可以把行动(action) 及其参数封装起来,于是这些行动可以被: + * 重复多次 + * 取消(如果该对象有实现的话) + * 取消后又再重做 + ### 示例: + +```swift +protocol DoorCommand { + func execute() -> String +} + +final class OpenCommand: DoorCommand { + let doors:String + + required init(doors: String) { + self.doors = doors + } + + func execute() -> String { + return "Opened \(doors)" + } +} + +final class CloseCommand: DoorCommand { + let doors:String + + required init(doors: String) { + self.doors = doors + } + + func execute() -> String { + return "Closed \(doors)" + } +} + +final class HAL9000DoorsOperations { + let openCommand: DoorCommand + let closeCommand: DoorCommand + + init(doors: String) { + self.openCommand = OpenCommand(doors:doors) + self.closeCommand = CloseCommand(doors:doors) + } + + func close() -> String { + return closeCommand.execute() + } + + func open() -> String { + return openCommand.execute() + } +} +``` + +### 用法 + +```swift +let podBayDoors = "Pod Bay Doors" +let doorModule = HAL9000DoorsOperations(doors:podBayDoors) + +doorModule.open() +doorModule.close() +``` + +🎶 解释器(Interpreter) + ------------------ + + 给定一种语言,定义他的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中句子。 + + ### 示例: + +```swift + +protocol IntegerExpression { + func evaluate(_ context: IntegerContext) -> Int + func replace(character: Character, integerExpression: IntegerExpression) -> IntegerExpression + func copied() -> IntegerExpression +} + +final class IntegerContext { + private var data: [Character:Int] = [:] + + func lookup(name: Character) -> Int { + return self.data[name]! + } + + func assign(expression: IntegerVariableExpression, value: Int) { + self.data[expression.name] = value + } +} + +final class IntegerVariableExpression: IntegerExpression { + let name: Character + + init(name: Character) { + self.name = name + } + + func evaluate(_ context: IntegerContext) -> Int { + return context.lookup(name: self.name) + } + + func replace(character name: Character, integerExpression: IntegerExpression) -> IntegerExpression { + if name == self.name { + return integerExpression.copied() + } else { + return IntegerVariableExpression(name: self.name) + } + } + + func copied() -> IntegerExpression { + return IntegerVariableExpression(name: self.name) + } +} + +final class AddExpression: IntegerExpression { + private var operand1: IntegerExpression + private var operand2: IntegerExpression + + init(op1: IntegerExpression, op2: IntegerExpression) { + self.operand1 = op1 + self.operand2 = op2 + } + + func evaluate(_ context: IntegerContext) -> Int { + return self.operand1.evaluate(context) + self.operand2.evaluate(context) + } + + func replace(character: Character, integerExpression: IntegerExpression) -> IntegerExpression { + return AddExpression(op1: operand1.replace(character: character, integerExpression: integerExpression), + op2: operand2.replace(character: character, integerExpression: integerExpression)) + } + + func copied() -> IntegerExpression { + return AddExpression(op1: self.operand1, op2: self.operand2) + } +} +``` + +### 用法 + +```swift +var context = IntegerContext() + +var a = IntegerVariableExpression(name: "A") +var b = IntegerVariableExpression(name: "B") +var c = IntegerVariableExpression(name: "C") + +var expression = AddExpression(op1: a, op2: AddExpression(op1: b, op2: c)) // a + (b + c) + +context.assign(expression: a, value: 2) +context.assign(expression: b, value: 1) +context.assign(expression: c, value: 3) + +var result = expression.evaluate(context) +``` + +🍫 迭代器(Iterator) + --------------- + + 迭代器模式可以让用户通过特定的接口巡访容器中的每一个元素而不用了解底层的实现。 + + ### 示例: + +```swift +struct Novella { + let name: String +} + +struct Novellas { + let novellas: [Novella] +} + +struct NovellasIterator: IteratorProtocol { + + private var current = 0 + private let novellas: [Novella] + + init(novellas: [Novella]) { + self.novellas = novellas + } + + mutating func next() -> Novella? { + defer { current += 1 } + return novellas.count > current ? novellas[current] : nil + } +} + +extension Novellas: Sequence { + func makeIterator() -> NovellasIterator { + return NovellasIterator(novellas: novellas) + } +} +``` + +### 用法 + +```swift +let greatNovellas = Novellas(novellas: [Novella(name: "The Mist")] ) + +for novella in greatNovellas { + print("I've read: \(novella)") +} +``` + +💐 中介者(Mediator) + --------------- + + 用一个中介者对象封装一系列的对象交互,中介者使各对象不需要显示地相互作用,从而使耦合松散,而且可以独立地改变它们之间的交互。 + + ### 示例: + +```swift +protocol Receiver { + associatedtype MessageType + func receive(message: MessageType) +} + +protocol Sender { + associatedtype MessageType + associatedtype ReceiverType: Receiver + + var recipients: [ReceiverType] { get } + + func send(message: MessageType) +} + +struct Programmer: Receiver { + let name: String + + init(name: String) { + self.name = name + } + + func receive(message: String) { + print("\(name) received: \(message)") + } +} + +final class MessageMediator: Sender { + internal var recipients: [Programmer] = [] + + func add(recipient: Programmer) { + recipients.append(recipient) + } + + func send(message: String) { + for recipient in recipients { + recipient.receive(message: message) + } + } +} + +``` + +### 用法 + +```swift +func spamMonster(message: String, worker: MessageMediator) { + worker.send(message: message) +} + +let messagesMediator = MessageMediator() + +let user0 = Programmer(name: "Linus Torvalds") +let user1 = Programmer(name: "Avadis 'Avie' Tevanian") +messagesMediator.add(recipient: user0) +messagesMediator.add(recipient: user1) + +spamMonster(message: "I'd Like to Add you to My Professional Network", worker: messagesMediator) + +``` + +💾 备忘录(Memento) +-------------- + +在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样就可以将该对象恢复到原先保存的状态 + +### 示例: + +```swift +typealias Memento = [String: String] +``` + +发起人(Originator) + +```swift +protocol MementoConvertible { + var memento: Memento { get } + init?(memento: Memento) +} + +struct GameState: MementoConvertible { + + private enum Keys { + static let chapter = "com.valve.halflife.chapter" + static let weapon = "com.valve.halflife.weapon" + } + + var chapter: String + var weapon: String + + init(chapter: String, weapon: String) { + self.chapter = chapter + self.weapon = weapon + } + + init?(memento: Memento) { + guard let mementoChapter = memento[Keys.chapter], + let mementoWeapon = memento[Keys.weapon] else { + return nil + } + + chapter = mementoChapter + weapon = mementoWeapon + } + + var memento: Memento { + return [ Keys.chapter: chapter, Keys.weapon: weapon ] + } +} +``` + +管理者(Caretaker) + +```swift +enum CheckPoint { + + private static let defaults = UserDefaults.standard + + static func save(_ state: MementoConvertible, saveName: String) { + defaults.set(state.memento, forKey: saveName) + defaults.synchronize() + } + + static func restore(saveName: String) -> Any? { + return defaults.object(forKey: saveName) + } +} +``` + +### 用法 + +```swift +var gameState = GameState(chapter: "Black Mesa Inbound", weapon: "Crowbar") + +gameState.chapter = "Anomalous Materials" +gameState.weapon = "Glock 17" +CheckPoint.save(gameState, saveName: "gameState1") + +gameState.chapter = "Unforeseen Consequences" +gameState.weapon = "MP5" +CheckPoint.save(gameState, saveName: "gameState2") + +gameState.chapter = "Office Complex" +gameState.weapon = "Crossbow" +CheckPoint.save(gameState, saveName: "gameState3") + +if let memento = CheckPoint.restore(saveName: "gameState1") as? Memento { + let finalState = GameState(memento: memento) + dump(finalState) +} +``` + +👓 观察者(Observer) +--------------- + +一个目标对象管理所有相依于它的观察者对象,并且在它本身的状态改变时主动发出通知 + +### 示例: + +```swift +protocol PropertyObserver : class { + func willChange(propertyName: String, newPropertyValue: Any?) + func didChange(propertyName: String, oldPropertyValue: Any?) +} + +final class TestChambers { + + weak var observer:PropertyObserver? + + private let testChamberNumberName = "testChamberNumber" + + var testChamberNumber: Int = 0 { + willSet(newValue) { + observer?.willChange(propertyName: testChamberNumberName, newPropertyValue: newValue) + } + didSet { + observer?.didChange(propertyName: testChamberNumberName, oldPropertyValue: oldValue) + } + } +} + +final class Observer : PropertyObserver { + func willChange(propertyName: String, newPropertyValue: Any?) { + if newPropertyValue as? Int == 1 { + print("Okay. Look. We both said a lot of things that you're going to regret.") + } + } + + func didChange(propertyName: String, oldPropertyValue: Any?) { + if oldPropertyValue as? Int == 0 { + print("Sorry about the mess. I've really let the place go since you killed me.") + } + } +} +``` + +### 用法 + +```swift +var observerInstance = Observer() +var testChambers = TestChambers() +testChambers.observer = observerInstance +testChambers.testChamberNumber += 1 +``` + +🐉 状态(State) +--------- + +在状态模式中,对象的行为是基于它的内部状态而改变的。 +这个模式允许某个类对象在运行时发生改变。 + +### 示例: + +```swift +final class Context { + private var state: State = UnauthorizedState() + + var isAuthorized: Bool { + get { return state.isAuthorized(context: self) } + } + + var userId: String? { + get { return state.userId(context: self) } + } + + func changeStateToAuthorized(userId: String) { + state = AuthorizedState(userId: userId) + } + + func changeStateToUnauthorized() { + state = UnauthorizedState() + } +} + +protocol State { + func isAuthorized(context: Context) -> Bool + func userId(context: Context) -> String? +} + +class UnauthorizedState: State { + func isAuthorized(context: Context) -> Bool { return false } + + func userId(context: Context) -> String? { return nil } +} + +class AuthorizedState: State { + let userId: String + + init(userId: String) { self.userId = userId } + + func isAuthorized(context: Context) -> Bool { return true } + + func userId(context: Context) -> String? { return userId } +} +``` + +### 用法 + +```swift +let userContext = Context() +(userContext.isAuthorized, userContext.userId) +userContext.changeStateToAuthorized(userId: "admin") +(userContext.isAuthorized, userContext.userId) // now logged in as "admin" +userContext.changeStateToUnauthorized() +(userContext.isAuthorized, userContext.userId) +``` + +💡 策略(Strategy) +-------------- + +对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。策略模式: +* 定义了一族算法(业务规则); +* 封装了每个算法; +* 这族的算法可互换代替(interchangeable)。 + +### 示例: + +```swift + +struct TestSubject { + let pupilDiameter: Double + let blushResponse: Double + let isOrganic: Bool +} + +protocol RealnessTesting: AnyObject { + func testRealness(_ testSubject: TestSubject) -> Bool +} + +final class VoightKampffTest: RealnessTesting { + func testRealness(_ testSubject: TestSubject) -> Bool { + return testSubject.pupilDiameter < 30.0 || testSubject.blushResponse == 0.0 + } +} + +final class GeneticTest: RealnessTesting { + func testRealness(_ testSubject: TestSubject) -> Bool { + return testSubject.isOrganic + } +} + +final class BladeRunner { + private let strategy: RealnessTesting + + init(test: RealnessTesting) { + self.strategy = test + } + + func testIfAndroid(_ testSubject: TestSubject) -> Bool { + return !strategy.testRealness(testSubject) + } +} + +``` + + ### 用法 + +```swift + +let rachel = TestSubject(pupilDiameter: 30.2, + blushResponse: 0.3, + isOrganic: false) + +// Deckard is using a traditional test +let deckard = BladeRunner(test: VoightKampffTest()) +let isRachelAndroid = deckard.testIfAndroid(rachel) + +// Gaff is using a very precise method +let gaff = BladeRunner(test: GeneticTest()) +let isDeckardAndroid = gaff.testIfAndroid(rachel) +``` + +🏃 访问者(Visitor) +-------------- + +封装某些作用于某种数据结构中各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。 + +### 示例: + +```swift +protocol PlanetVisitor { + func visit(planet: PlanetAlderaan) + func visit(planet: PlanetCoruscant) + func visit(planet: PlanetTatooine) + func visit(planet: MoonJedha) +} + +protocol Planet { + func accept(visitor: PlanetVisitor) +} + +final class MoonJedha: Planet { + func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) } +} + +final class PlanetAlderaan: Planet { + func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) } +} + +final class PlanetCoruscant: Planet { + func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) } +} + +final class PlanetTatooine: Planet { + func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) } +} + +final class NameVisitor: PlanetVisitor { + var name = "" + + func visit(planet: PlanetAlderaan) { name = "Alderaan" } + func visit(planet: PlanetCoruscant) { name = "Coruscant" } + func visit(planet: PlanetTatooine) { name = "Tatooine" } + func visit(planet: MoonJedha) { name = "Jedha" } +} + +``` + +### 用法 + +```swift +let planets: [Planet] = [PlanetAlderaan(), PlanetCoruscant(), PlanetTatooine(), MoonJedha()] + +let names = planets.map { (planet: Planet) -> String in + let visitor = NameVisitor() + planet.accept(visitor: visitor) + + return visitor.name +} + +names +``` + + + 创建型模式 + ======== + + > 创建型模式是处理对象创建的设计模式,试图根据实际情况使用合适的方式创建对象。基本的对象创建方式可能会导致设计上的问题,或增加设计的复杂度。创建型模式通过以某种方式控制对象的创建来解决问题。 + > + >**来源:** [维基百科](https://zh.wikipedia.org/wiki/%E5%89%B5%E5%BB%BA%E5%9E%8B%E6%A8%A1%E5%BC%8F) + + + + + +🌰 抽象工厂(Abstract Factory) +------------- + +抽象工厂模式提供了一种方式,可以将一组具有同一主题的单独的工厂封装起来。在正常使用中,客户端程序需要创建抽象工厂的具体实现,然后使用抽象工厂作为接口来创建这一主题的具体对象。 + +### 示例: + +协议 + +```swift + +protocol BurgerDescribing { + var ingredients: [String] { get } +} + +struct CheeseBurger: BurgerDescribing { + let ingredients: [String] +} + +protocol BurgerMaking { + func make() -> BurgerDescribing +} + +// 工厂方法实现 + +final class BigKahunaBurger: BurgerMaking { + func make() -> BurgerDescribing { + return CheeseBurger(ingredients: ["Cheese", "Burger", "Lettuce", "Tomato"]) + } +} + +final class JackInTheBox: BurgerMaking { + func make() -> BurgerDescribing { + return CheeseBurger(ingredients: ["Cheese", "Burger", "Tomato", "Onions"]) + } +} + +``` + +抽象工厂 + +```swift + +enum BurgerFactoryType: BurgerMaking { + + case bigKahuna + case jackInTheBox + + func make() -> BurgerDescribing { + switch self { + case .bigKahuna: + return BigKahunaBurger().make() + case .jackInTheBox: + return JackInTheBox().make() + } + } +} +``` + +### 用法 + +```swift +let bigKahuna = BurgerFactoryType.bigKahuna.make() +let jackInTheBox = BurgerFactoryType.jackInTheBox.make() +``` + +👷 生成器(Builder) +-------------- + +一种对象构建模式。它可以将复杂对象的建造过程抽象出来(抽象类别),使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象。 + +### 示例: + +```swift +final class DeathStarBuilder { + + var x: Double? + var y: Double? + var z: Double? + + typealias BuilderClosure = (DeathStarBuilder) -> () + + init(buildClosure: BuilderClosure) { + buildClosure(self) + } +} + +struct DeathStar : CustomStringConvertible { + + let x: Double + let y: Double + let z: Double + + init?(builder: DeathStarBuilder) { + + if let x = builder.x, let y = builder.y, let z = builder.z { + self.x = x + self.y = y + self.z = z + } else { + return nil + } + } + + var description:String { + return "Death Star at (x:\(x) y:\(y) z:\(z))" + } +} +``` + +### 用法 + +```swift +let empire = DeathStarBuilder { builder in + builder.x = 0.1 + builder.y = 0.2 + builder.z = 0.3 +} + +let deathStar = DeathStar(builder:empire) +``` + +🏭 工厂方法(Factory Method) +----------------------- + +定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类。工厂方法让类的实例化推迟到子类中进行。 + +### 示例: + +```swift +protocol CurrencyDescribing { + var symbol: String { get } + var code: String { get } +} + +final class Euro: CurrencyDescribing { + var symbol: String { + return "€" + } + + var code: String { + return "EUR" + } +} + +final class UnitedStatesDolar: CurrencyDescribing { + var symbol: String { + return "$" + } + + var code: String { + return "USD" + } +} + +enum Country { + case unitedStates + case spain + case uk + case greece +} + +enum CurrencyFactory { + static func currency(for country: Country) -> CurrencyDescribing? { + + switch country { + case .spain, .greece: + return Euro() + case .unitedStates: + return UnitedStatesDolar() + default: + return nil + } + + } +} +``` + +### 用法 + +```swift +let noCurrencyCode = "No Currency Code Available" + +CurrencyFactory.currency(for: .greece)?.code ?? noCurrencyCode +CurrencyFactory.currency(for: .spain)?.code ?? noCurrencyCode +CurrencyFactory.currency(for: .unitedStates)?.code ?? noCurrencyCode +CurrencyFactory.currency(for: .uk)?.code ?? noCurrencyCode +``` + +🃏 原型(Prototype) +-------------- + +通过“复制”一个已经存在的实例来返回新的实例,而不是新建实例。被复制的实例就是我们所称的“原型”,这个原型是可定制的。 + +### 示例: + +```swift +struct MoonWorker { + + let name: String + var health: Int = 100 + + init(name: String) { + self.name = name + } + + func clone() -> MoonWorker { + return MoonWorker(name: name) + } +} +``` + +### 用法 + +```swift +let prototype = MoonWorker(name: "Sam Bell") + +var bell1 = prototype.clone() +bell1.health = 12 + +var bell2 = prototype.clone() +bell2.health = 23 + +var bell3 = prototype.clone() +bell3.health = 0 +``` + +💍 单例(Singleton) +-------------- + +单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为 + +### 示例: + +```swift +final class ElonMusk { + + static let shared = ElonMusk() + + private init() { + // Private initialization to ensure just one instance is created. + } +} +``` + +### 用法 + +```swift +let elon = ElonMusk.shared // There is only one Elon Musk folks. +``` + + +结构型模式(Structural) +==================== + +> 在软件工程中结构型模式是设计模式,借由一以贯之的方式来了解元件间的关系,以简化设计。 +> +>**来源:** [维基百科](https://zh.wikipedia.org/wiki/%E7%B5%90%E6%A7%8B%E5%9E%8B%E6%A8%A1%E5%BC%8F) + + + + +🔌 适配器(Adapter) +-------------- + +适配器模式有时候也称包装样式或者包装(wrapper)。将一个类的接口转接成用户所期待的。一个适配使得因接口不兼容而不能在一起工作的类工作在一起,做法是将类自己的接口包裹在一个已存在的类中。 + +### 示例: + +```swift +protocol NewDeathStarSuperLaserAiming { + var angleV: Double { get } + var angleH: Double { get } +} +``` + +**被适配者** + +```swift +struct OldDeathStarSuperlaserTarget { + let angleHorizontal: Float + let angleVertical: Float + + init(angleHorizontal: Float, angleVertical: Float) { + self.angleHorizontal = angleHorizontal + self.angleVertical = angleVertical + } +} +``` + +**适配器** + +```swift +struct NewDeathStarSuperlaserTarget: NewDeathStarSuperLaserAiming { + + private let target: OldDeathStarSuperlaserTarget + + var angleV: Double { + return Double(target.angleVertical) + } + + var angleH: Double { + return Double(target.angleHorizontal) + } + + init(_ target: OldDeathStarSuperlaserTarget) { + self.target = target + } +} +``` + +### 用法 + +```swift +let target = OldDeathStarSuperlaserTarget(angleHorizontal: 14.0, angleVertical: 12.0) +let newFormat = NewDeathStarSuperlaserTarget(target) + +newFormat.angleH +newFormat.angleV +``` + +🌉 桥接(Bridge) +----------- + +桥接模式将抽象部分与实现部分分离,使它们都可以独立的变化。 + +### 示例: + +```swift +protocol Switch { + var appliance: Appliance { get set } + func turnOn() +} + +protocol Appliance { + func run() +} + +final class RemoteControl: Switch { + var appliance: Appliance + + func turnOn() { + self.appliance.run() + } + + init(appliance: Appliance) { + self.appliance = appliance + } +} + +final class TV: Appliance { + func run() { + print("tv turned on"); + } +} + +final class VacuumCleaner: Appliance { + func run() { + print("vacuum cleaner turned on") + } +} +``` + +### 用法 + +```swift +let tvRemoteControl = RemoteControl(appliance: TV()) +tvRemoteControl.turnOn() + +let fancyVacuumCleanerRemoteControl = RemoteControl(appliance: VacuumCleaner()) +fancyVacuumCleanerRemoteControl.turnOn() +``` + +🌿 组合(Composite) +-------------- + +将对象组合成树形结构以表示‘部分-整体’的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。 + +### 示例: + +组件(Component) + +```swift +protocol Shape { + func draw(fillColor: String) +} +``` + +叶子节点(Leafs) + +```swift +final class Square: Shape { + func draw(fillColor: String) { + print("Drawing a Square with color \(fillColor)") + } +} + +final class Circle: Shape { + func draw(fillColor: String) { + print("Drawing a circle with color \(fillColor)") + } +} + +``` + +组合 + +```swift +final class Whiteboard: Shape { + + private lazy var shapes = [Shape]() + + init(_ shapes: Shape...) { + self.shapes = shapes + } + + func draw(fillColor: String) { + for shape in self.shapes { + shape.draw(fillColor: fillColor) + } + } +} +``` + +### 用法 + +```swift +var whiteboard = Whiteboard(Circle(), Square()) +whiteboard.draw(fillColor: "Red") +``` + +🍧 修饰(Decorator) +-------------- + +修饰模式,是面向对象编程领域中,一种动态地往一个类中添加新的行为的设计模式。 +就功能而言,修饰模式相比生成子类更为灵活,这样可以给某个对象而不是整个类添加一些功能。 + +### 示例: + +```swift +protocol CostHaving { + var cost: Double { get } +} + +protocol IngredientsHaving { + var ingredients: [String] { get } +} + +typealias BeverageDataHaving = CostHaving & IngredientsHaving + +struct SimpleCoffee: BeverageDataHaving { + let cost: Double = 1.0 + let ingredients = ["Water", "Coffee"] +} + +protocol BeverageHaving: BeverageDataHaving { + var beverage: BeverageDataHaving { get } +} + +struct Milk: BeverageHaving { + + let beverage: BeverageDataHaving + + var cost: Double { + return beverage.cost + 0.5 + } + + var ingredients: [String] { + return beverage.ingredients + ["Milk"] + } +} + +struct WhipCoffee: BeverageHaving { + + let beverage: BeverageDataHaving + + var cost: Double { + return beverage.cost + 0.5 + } + + var ingredients: [String] { + return beverage.ingredients + ["Whip"] + } +} +``` + +### 用法 + +```swift +var someCoffee: BeverageDataHaving = SimpleCoffee() +print("Cost: \(someCoffee.cost); Ingredients: \(someCoffee.ingredients)") +someCoffee = Milk(beverage: someCoffee) +print("Cost: \(someCoffee.cost); Ingredients: \(someCoffee.ingredients)") +someCoffee = WhipCoffee(beverage: someCoffee) +print("Cost: \(someCoffee.cost); Ingredients: \(someCoffee.ingredients)") +``` + +🎁 外观(Facade) +----------- + +外观模式为子系统中的一组接口提供一个统一的高层接口,使得子系统更容易使用。 + +### 示例: + +```swift +final class Defaults { + + private let defaults: UserDefaults + + init(defaults: UserDefaults = .standard) { + self.defaults = defaults + } + + subscript(key: String) -> String? { + get { + return defaults.string(forKey: key) + } + + set { + defaults.set(newValue, forKey: key) + } + } +} +``` + +### 用法 + +```swift +let storage = Defaults() + +// Store +storage["Bishop"] = "Disconnect me. I’d rather be nothing" + +// Read +storage["Bishop"] +``` + +🍃 享元(Flyweight) +-------------- + +使用共享物件,用来尽可能减少内存使用量以及分享资讯给尽可能多的相似物件;它适合用于当大量物件只是重复因而导致无法令人接受的使用大量内存。 + +### 示例: + +```swift +// 特指咖啡生成的对象会是享元 +struct SpecialityCoffee { + let origin: String +} + +protocol CoffeeSearching { + func search(origin: String) -> SpecialityCoffee? +} + +// 菜单充当特制咖啡享元对象的工厂和缓存 +final class Menu: CoffeeSearching { + + private var coffeeAvailable: [String: SpecialityCoffee] = [:] + + func search(origin: String) -> SpecialityCoffee? { + if coffeeAvailable.index(forKey: origin) == nil { + coffeeAvailable[origin] = SpecialityCoffee(origin: origin) + } + + return coffeeAvailable[origin] + } +} + +final class CoffeeShop { + private var orders: [Int: SpecialityCoffee] = [:] + private let menu: CoffeeSearching + + init(menu: CoffeeSearching) { + self.menu = menu + } + + func takeOrder(origin: String, table: Int) { + orders[table] = menu.search(origin: origin) + } + + func serve() { + for (table, origin) in orders { + print("Serving \(origin) to table \(table)") + } + } +} +``` + +### 用法 + +```swift +let coffeeShop = CoffeeShop(menu: Menu()) + +coffeeShop.takeOrder(origin: "Yirgacheffe, Ethiopia", table: 1) +coffeeShop.takeOrder(origin: "Buziraguhindwa, Burundi", table: 3) + +coffeeShop.serve() +``` + +☔ 保护代理模式(Protection Proxy) +------------------ + +在代理模式中,创建一个类代表另一个底层类的功能。 +保护代理用于限制访问。 + +### 示例: + +```swift +protocol DoorOpening { + func open(doors: String) -> String +} + +final class HAL9000: DoorOpening { + func open(doors: String) -> String { + return ("HAL9000: Affirmative, Dave. I read you. Opened \(doors).") + } +} + +final class CurrentComputer: DoorOpening { + private var computer: HAL9000! + + func authenticate(password: String) -> Bool { + + guard password == "pass" else { + return false + } + + computer = HAL9000() + + return true + } + + func open(doors: String) -> String { + + guard computer != nil else { + return "Access Denied. I'm afraid I can't do that." + } + + return computer.open(doors: doors) + } +} +``` + +### 用法 + +```swift +let computer = CurrentComputer() +let podBay = "Pod Bay Doors" + +computer.open(doors: podBay) + +computer.authenticate(password: "pass") +computer.open(doors: podBay) +``` + +🍬 虚拟代理(Virtual Proxy) +---------------- + +在代理模式中,创建一个类代表另一个底层类的功能。 +虚拟代理用于对象的需时加载。 + +### 示例: + +```swift +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() + } +} +``` + +### 用法 + +```swift +let humanInterface = HEVSuitHumanInterface() +humanInterface.administerMorphine() +``` + + +Info +==== + +📖 Descriptions from: [Gang of Four Design Patterns Reference Sheet](http://www.blackwasp.co.uk/GangOfFour.aspx) diff --git a/README.md b/README.md index a6ee6b4..4790bae 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,17 @@ -设计模式(Swift 5.0 实现) +Design Patterns implemented in Swift 5.0 ======================================== -👷 源项目由 [@nsmeme](http://twitter.com/nsmeme) (Oktawian Chojnacki) 维护。 +A short cheat-sheet with Xcode 10.2 Playground ([Design-Patterns.playground.zip](https://raw.githubusercontent.com/ochococo/Design-Patterns-In-Swift/master/Design-Patterns.playground.zip)). -🇨🇳 中文版由 [@binglogo](https://twitter.com/binglogo) 整理翻译。 +### [🇨🇳中文版](https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/GENERATE-CN.md) + +👷 Project started by: [@nsmeme](http://twitter.com/nsmeme) (Oktawian Chojnacki) + +👷 中文版由 [@binglogo](https://twitter.com/binglogo) (棒棒彬) 整理翻译。 + +🚀 How to generate README, Playground and zip from source: [GENERATE.md](https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/GENERATE.md) ```swift @@ -13,38 +19,38 @@ print("Welcome!") ``` -## 目录 +## Table of Contents -| [行为型模式](#行为型模式) | [创建型模式](#创建型模式) | [结构型模式](#结构型模式structural) | -| ------------------------------------------------------------ | --------------------------------------------------------- | ------------------------------------------------------------ | -| [🐝 责任链 Chain Of Responsibility](#-责任链chain-of-responsibility) | [🌰 抽象工厂 Abstract Factory](#-抽象工厂abstract-factory) | [🔌 适配器 Adapter](#-适配器adapter) | -| [👫 命令 Command](#-命令command) | [👷 生成器 Builder](#-生成器builder) | [🌉 桥接 Bridge](#-桥接bridge) | -| [🎶 解释器 Interpreter](#-解释器interpreter) | [🏭 工厂方法 Factory Method](#-工厂方法factory-method) | [🌿 组合 Composite](#-组合composite) | -| [🍫 迭代器 Iterator](#-迭代器iterator) | [🃏 原型 Prototype](#-原型prototype) | [🍧 修饰 Decorator](#-修饰decorator) | -| [💐 中介者 Mediator](#-中介者mediator) | [💍 单例 Singleton](#-单例singleton) | [🎁 外观 Façade](#-外观facade) | -| [💾 备忘录 Memento](#-备忘录memento) | | [🍃 享元 Flyweight](#-享元flyweight) | -| [👓 观察者 Observer](#-观察者observer) | | [☔ 保护代理 Protection Proxy](#-保护代理模式protection-proxy) | -| [🐉 状态 State](#-状态state) | | [🍬 虚拟代理 Virtual Proxy](#-虚拟代理virtual-proxy) | -| [💡 策略 Strategy](#-策略strategy) | | | -| [🏃 访问者 Visitor](#-访问者visitor) | | | +| [Behavioral](#behavioral) | [Creational](#creational) | [Structural](#structural) | +| ------------------------------------------------------ | ---------------------------------------- | ---------------------------------------- | +| [🐝 Chain Of Responsibility](#-chain-of-responsibility) | [🌰 Abstract Factory](#-abstract-factory) | [🔌 Adapter](#-adapter) | +| [👫 Command](#-command) | [👷 Builder](#-builder) | [🌉 Bridge](#-bridge) | +| [🎶 Interpreter](#-interpreter) | [🏭 Factory Method](#-factory-method) | [🌿 Composite](#-composite) | +| [🍫 Iterator](#-iterator) | [🃏 Prototype](#-prototype) | [🍧 Decorator](#-decorator) | +| [💐 Mediator](#-mediator) | [💍 Singleton](#-singleton) | [🎁 Façade](#-fa-ade) | +| [💾 Memento](#-memento) | | [🍃 Flyweight](#-flyweight) | +| [👓 Observer](#-observer) | | [☔ Protection Proxy](#-protection-proxy) | +| [🐉 State](#-state) | | [🍬 Virtual Proxy](#-virtual-proxy) | +| [💡 Strategy](#-strategy) | | | +| [🏃 Visitor](#-visitor) | | | - 行为型模式 - ======== - - >在软件工程中, 行为型模式为设计模式的一种类型,用来识别对象之间的常用交流模式并加以实现。如此,可在进行这些交流活动时增强弹性。 - > - >**来源:** [维基百科](https://zh.wikipedia.org/wiki/%E8%A1%8C%E7%82%BA%E5%9E%8B%E6%A8%A1%E5%BC%8F) +Behavioral +========== + +>In software engineering, behavioral design patterns are design patterns that identify common communication patterns between objects and realize these patterns. By doing so, these patterns increase flexibility in carrying out this communication. +> +>**Source:** [wikipedia.org](http://en.wikipedia.org/wiki/Behavioral_pattern) -🐝 责任链(Chain Of Responsibility) ------------------------------- +🐝 Chain Of Responsibility +-------------------------- -责任链模式在面向对象程式设计里是一种软件设计模式,它包含了一些命令对象和一系列的处理对象。每一个处理对象决定它能处理哪些命令对象,它也知道如何将它不能处理的命令对象传递给该链中的下一个处理对象。 +The chain of responsibility pattern is used to process varied requests, each of which may be dealt with by a different handler. -### 示例: +### Example: ```swift @@ -124,28 +130,27 @@ final class ATM: Withdrawing { } ``` - ### 用法 - +### Usage + ```swift -// 创建一系列的钱堆,并将其链接起来:10<20<50<100 +// Create piles of money and link them together 10 < 20 < 50 < 100.** let ten = MoneyPile(value: 10, quantity: 6, next: nil) let twenty = MoneyPile(value: 20, quantity: 2, next: ten) let fifty = MoneyPile(value: 50, quantity: 2, next: twenty) let hundred = MoneyPile(value: 100, quantity: 1, next: fifty) -// 创建 ATM 实例 +// Build ATM. var atm = ATM(hundred: hundred, fifty: fifty, twenty: twenty, ten: ten) atm.withdraw(amount: 310) // Cannot because ATM has only 300 atm.withdraw(amount: 100) // Can withdraw - 1x100 ``` -👫 命令(Command) - ------------ - 命令模式是一种设计模式,它尝试以对象来代表实际行动。命令对象可以把行动(action) 及其参数封装起来,于是这些行动可以被: - * 重复多次 - * 取消(如果该对象有实现的话) - * 取消后又再重做 - ### 示例: +👫 Command +---------- + +The command pattern is used to express a request, including the call to be made and all of its required parameters, in a command object. The command may then be executed immediately or held for later use. + +### Example: ```swift protocol DoorCommand { @@ -195,7 +200,7 @@ final class HAL9000DoorsOperations { } ``` -### 用法 +### Usage: ```swift let podBayDoors = "Pod Bay Doors" @@ -205,12 +210,12 @@ doorModule.open() doorModule.close() ``` -🎶 解释器(Interpreter) - ------------------ +🎶 Interpreter +-------------- - 给定一种语言,定义他的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中句子。 +The interpreter pattern is used to evaluate sentences in a language. - ### 示例: +### Example ```swift @@ -280,7 +285,7 @@ final class AddExpression: IntegerExpression { } ``` -### 用法 +### Usage ```swift var context = IntegerContext() @@ -298,12 +303,12 @@ context.assign(expression: c, value: 3) var result = expression.evaluate(context) ``` -🍫 迭代器(Iterator) - --------------- +🍫 Iterator +----------- - 迭代器模式可以让用户通过特定的接口巡访容器中的每一个元素而不用了解底层的实现。 - - ### 示例: +The iterator pattern is used to provide a standard interface for traversing a collection of items in an aggregate object without the need to understand its underlying structure. + +### Example: ```swift struct Novella { @@ -336,7 +341,7 @@ extension Novellas: Sequence { } ``` -### 用法 +### Usage ```swift let greatNovellas = Novellas(novellas: [Novella(name: "The Mist")] ) @@ -346,12 +351,12 @@ for novella in greatNovellas { } ``` -💐 中介者(Mediator) - --------------- +💐 Mediator +----------- - 用一个中介者对象封装一系列的对象交互,中介者使各对象不需要显示地相互作用,从而使耦合松散,而且可以独立地改变它们之间的交互。 +The mediator pattern is used to reduce coupling between classes that communicate with each other. Instead of classes communicating directly, and thus requiring knowledge of their implementation, the classes send messages via a mediator object. - ### 示例: +### Example ```swift protocol Receiver { @@ -396,7 +401,7 @@ final class MessageMediator: Sender { ``` -### 用法 +### Usage ```swift func spamMonster(message: String, worker: MessageMediator) { @@ -414,18 +419,18 @@ spamMonster(message: "I'd Like to Add you to My Professional Network", worker: m ``` -💾 备忘录(Memento) --------------- +💾 Memento +---------- -在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样就可以将该对象恢复到原先保存的状态 +The memento pattern is used to capture the current state of an object and store it in such a manner that it can be restored at a later time without breaking the rules of encapsulation. -### 示例: +### Example ```swift typealias Memento = [String: String] ``` -发起人(Originator) +Originator ```swift protocol MementoConvertible { @@ -464,7 +469,7 @@ struct GameState: MementoConvertible { } ``` -管理者(Caretaker) +Caretaker ```swift enum CheckPoint { @@ -482,7 +487,7 @@ enum CheckPoint { } ``` -### 用法 +### Usage ```swift var gameState = GameState(chapter: "Black Mesa Inbound", weapon: "Crowbar") @@ -505,12 +510,13 @@ if let memento = CheckPoint.restore(saveName: "gameState1") as? Memento { } ``` -👓 观察者(Observer) ---------------- +👓 Observer +----------- -一个目标对象管理所有相依于它的观察者对象,并且在它本身的状态改变时主动发出通知 +The observer pattern is used to allow an object to publish changes to its state. +Other objects subscribe to be immediately notified of any changes. -### 示例: +### Example ```swift protocol PropertyObserver : class { @@ -549,7 +555,7 @@ final class Observer : PropertyObserver { } ``` -### 用法 +### Usage ```swift var observerInstance = Observer() @@ -558,13 +564,13 @@ testChambers.observer = observerInstance testChambers.testChamberNumber += 1 ``` -🐉 状态(State) +🐉 State --------- -在状态模式中,对象的行为是基于它的内部状态而改变的。 -这个模式允许某个类对象在运行时发生改变。 +The state pattern is used to alter the behaviour of an object as its internal state changes. +The pattern allows the class for an object to apparently change at run-time. -### 示例: +### Example ```swift final class Context { @@ -609,7 +615,7 @@ class AuthorizedState: State { } ``` -### 用法 +### Usage ```swift let userContext = Context() @@ -620,15 +626,12 @@ userContext.changeStateToUnauthorized() (userContext.isAuthorized, userContext.userId) ``` -💡 策略(Strategy) --------------- +💡 Strategy +----------- -对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。策略模式: -* 定义了一族算法(业务规则); -* 封装了每个算法; -* 这族的算法可互换代替(interchangeable)。 +The strategy pattern is used to create an interchangeable family of algorithms from which the required process is chosen at run-time. -### 示例: +### Example ```swift @@ -668,7 +671,7 @@ final class BladeRunner { ``` - ### 用法 + ### Usage ```swift @@ -685,12 +688,12 @@ let gaff = BladeRunner(test: GeneticTest()) let isDeckardAndroid = gaff.testIfAndroid(rachel) ``` -🏃 访问者(Visitor) --------------- +🏃 Visitor +---------- -封装某些作用于某种数据结构中各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。 +The visitor pattern is used to separate a relatively complex set of structured data classes from the functionality that may be performed upon the data that they hold. -### 示例: +### Example ```swift protocol PlanetVisitor { @@ -731,7 +734,7 @@ final class NameVisitor: PlanetVisitor { ``` -### 用法 +### Usage ```swift let planets: [Planet] = [PlanetAlderaan(), PlanetCoruscant(), PlanetTatooine(), MoonJedha()] @@ -747,25 +750,25 @@ names ``` - 创建型模式 - ======== - - > 创建型模式是处理对象创建的设计模式,试图根据实际情况使用合适的方式创建对象。基本的对象创建方式可能会导致设计上的问题,或增加设计的复杂度。创建型模式通过以某种方式控制对象的创建来解决问题。 - > - >**来源:** [维基百科](https://zh.wikipedia.org/wiki/%E5%89%B5%E5%BB%BA%E5%9E%8B%E6%A8%A1%E5%BC%8F) - +Creational +========== +> In software engineering, creational design patterns are design patterns that deal with object creation mechanisms, trying to create objects in a manner suitable to the situation. The basic form of object creation could result in design problems or added complexity to the design. Creational design patterns solve this problem by somehow controlling this object creation. +> +>**Source:** [wikipedia.org](http://en.wikipedia.org/wiki/Creational_pattern) -🌰 抽象工厂(Abstract Factory) -------------- -抽象工厂模式提供了一种方式,可以将一组具有同一主题的单独的工厂封装起来。在正常使用中,客户端程序需要创建抽象工厂的具体实现,然后使用抽象工厂作为接口来创建这一主题的具体对象。 +🌰 Abstract Factory +------------------- -### 示例: +The abstract factory pattern is used to provide a client with a set of related or dependant objects. +The "family" of objects created by the factory are determined at run-time. -协议 +### Example + +Protocols ```swift @@ -781,7 +784,7 @@ protocol BurgerMaking { func make() -> BurgerDescribing } -// 工厂方法实现 +// Number implementations with factory methods final class BigKahunaBurger: BurgerMaking { func make() -> BurgerDescribing { @@ -797,7 +800,7 @@ final class JackInTheBox: BurgerMaking { ``` -抽象工厂 +Abstract factory ```swift @@ -817,19 +820,20 @@ enum BurgerFactoryType: BurgerMaking { } ``` -### 用法 +### Usage ```swift let bigKahuna = BurgerFactoryType.bigKahuna.make() let jackInTheBox = BurgerFactoryType.jackInTheBox.make() ``` -👷 生成器(Builder) --------------- +👷 Builder +---------- -一种对象构建模式。它可以将复杂对象的建造过程抽象出来(抽象类别),使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象。 +The builder pattern is used to create complex objects with constituent parts that must be created in the same order or using a specific algorithm. +An external class controls the construction algorithm. -### 示例: +### Example ```swift final class DeathStarBuilder { @@ -868,7 +872,7 @@ struct DeathStar : CustomStringConvertible { } ``` -### 用法 +### Usage ```swift let empire = DeathStarBuilder { builder in @@ -880,12 +884,12 @@ let empire = DeathStarBuilder { builder in let deathStar = DeathStar(builder:empire) ``` -🏭 工厂方法(Factory Method) ------------------------ +🏭 Factory Method +----------------- -定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类。工厂方法让类的实例化推迟到子类中进行。 +The factory pattern is used to replace class constructors, abstracting the process of object generation so that the type of the object instantiated can be determined at run-time. -### 示例: +### Example ```swift protocol CurrencyDescribing { @@ -936,7 +940,7 @@ enum CurrencyFactory { } ``` -### 用法 +### Usage ```swift let noCurrencyCode = "No Currency Code Available" @@ -947,12 +951,13 @@ CurrencyFactory.currency(for: .unitedStates)?.code ?? noCurrencyCode CurrencyFactory.currency(for: .uk)?.code ?? noCurrencyCode ``` -🃏 原型(Prototype) --------------- +🃏 Prototype +------------ -通过“复制”一个已经存在的实例来返回新的实例,而不是新建实例。被复制的实例就是我们所称的“原型”,这个原型是可定制的。 +The prototype pattern is used to instantiate a new object by copying all of the properties of an existing object, creating an independent clone. +This practise is particularly useful when the construction of a new object is inefficient. -### 示例: +### Example ```swift struct MoonWorker { @@ -970,7 +975,7 @@ struct MoonWorker { } ``` -### 用法 +### Usage ```swift let prototype = MoonWorker(name: "Sam Bell") @@ -985,12 +990,14 @@ var bell3 = prototype.clone() bell3.health = 0 ``` -💍 单例(Singleton) --------------- +💍 Singleton +------------ -单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为 +The singleton pattern ensures that only one object of a particular class is ever created. +All further references to objects of the singleton class refer to the same underlying instance. +There are very few applications, do not overuse this pattern! -### 示例: +### Example: ```swift final class ElonMusk { @@ -1003,29 +1010,29 @@ final class ElonMusk { } ``` -### 用法 +### Usage: ```swift let elon = ElonMusk.shared // There is only one Elon Musk folks. ``` -结构型模式(Structural) -==================== +Structural +========== -> 在软件工程中结构型模式是设计模式,借由一以贯之的方式来了解元件间的关系,以简化设计。 +>In software engineering, structural design patterns are design patterns that ease the design by identifying a simple way to realize relationships between entities. > ->**来源:** [维基百科](https://zh.wikipedia.org/wiki/%E7%B5%90%E6%A7%8B%E5%9E%8B%E6%A8%A1%E5%BC%8F) +>**Source:** [wikipedia.org](http://en.wikipedia.org/wiki/Structural_pattern) -🔌 适配器(Adapter) --------------- +🔌 Adapter +---------- -适配器模式有时候也称包装样式或者包装(wrapper)。将一个类的接口转接成用户所期待的。一个适配使得因接口不兼容而不能在一起工作的类工作在一起,做法是将类自己的接口包裹在一个已存在的类中。 +The adapter pattern is used to provide a link between two otherwise incompatible types by wrapping the "adaptee" with a class that supports the interface required by the client. -### 示例: +### Example ```swift protocol NewDeathStarSuperLaserAiming { @@ -1034,7 +1041,7 @@ protocol NewDeathStarSuperLaserAiming { } ``` -**被适配者** +**Adaptee** ```swift struct OldDeathStarSuperlaserTarget { @@ -1048,7 +1055,7 @@ struct OldDeathStarSuperlaserTarget { } ``` -**适配器** +**Adapter** ```swift struct NewDeathStarSuperlaserTarget: NewDeathStarSuperLaserAiming { @@ -1069,7 +1076,7 @@ struct NewDeathStarSuperlaserTarget: NewDeathStarSuperLaserAiming { } ``` -### 用法 +### Usage ```swift let target = OldDeathStarSuperlaserTarget(angleHorizontal: 14.0, angleVertical: 12.0) @@ -1079,12 +1086,12 @@ newFormat.angleH newFormat.angleV ``` -🌉 桥接(Bridge) ------------ +🌉 Bridge +---------- -桥接模式将抽象部分与实现部分分离,使它们都可以独立的变化。 +The bridge pattern is used to separate the abstract elements of a class from the implementation details, providing the means to replace the implementation details without modifying the abstraction. -### 示例: +### Example ```swift protocol Switch { @@ -1121,7 +1128,7 @@ final class VacuumCleaner: Appliance { } ``` -### 用法 +### Usage ```swift let tvRemoteControl = RemoteControl(appliance: TV()) @@ -1131,14 +1138,14 @@ let fancyVacuumCleanerRemoteControl = RemoteControl(appliance: VacuumCleaner()) fancyVacuumCleanerRemoteControl.turnOn() ``` -🌿 组合(Composite) --------------- +🌿 Composite +------------- -将对象组合成树形结构以表示‘部分-整体’的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。 +The composite pattern is used to create hierarchical, recursive tree structures of related objects where any element of the structure may be accessed and utilised in a standard manner. -### 示例: +### Example -组件(Component) +Component ```swift protocol Shape { @@ -1146,7 +1153,7 @@ protocol Shape { } ``` -叶子节点(Leafs) +Leafs ```swift final class Square: Shape { @@ -1163,7 +1170,7 @@ final class Circle: Shape { ``` -组合 +Composite ```swift final class Whiteboard: Shape { @@ -1182,20 +1189,20 @@ final class Whiteboard: Shape { } ``` -### 用法 +### Usage: ```swift var whiteboard = Whiteboard(Circle(), Square()) whiteboard.draw(fillColor: "Red") ``` -🍧 修饰(Decorator) --------------- +🍧 Decorator +------------ -修饰模式,是面向对象编程领域中,一种动态地往一个类中添加新的行为的设计模式。 -就功能而言,修饰模式相比生成子类更为灵活,这样可以给某个对象而不是整个类添加一些功能。 +The decorator pattern is used to extend or alter the functionality of objects at run- time by wrapping them in an object of a decorator class. +This provides a flexible alternative to using inheritance to modify behaviour. -### 示例: +### Example ```swift protocol CostHaving { @@ -1244,7 +1251,7 @@ struct WhipCoffee: BeverageHaving { } ``` -### 用法 +### Usage: ```swift var someCoffee: BeverageDataHaving = SimpleCoffee() @@ -1255,12 +1262,12 @@ someCoffee = WhipCoffee(beverage: someCoffee) print("Cost: \(someCoffee.cost); Ingredients: \(someCoffee.ingredients)") ``` -🎁 外观(Facade) ------------ +🎁 Façade +--------- -外观模式为子系统中的一组接口提供一个统一的高层接口,使得子系统更容易使用。 +The facade pattern is used to define a simplified interface to a more complex subsystem. -### 示例: +### Example ```swift final class Defaults { @@ -1283,7 +1290,7 @@ final class Defaults { } ``` -### 用法 +### Usage ```swift let storage = Defaults() @@ -1295,15 +1302,12 @@ storage["Bishop"] = "Disconnect me. I’d rather be nothing" storage["Bishop"] ``` -🍃 享元(Flyweight) --------------- - -使用共享物件,用来尽可能减少内存使用量以及分享资讯给尽可能多的相似物件;它适合用于当大量物件只是重复因而导致无法令人接受的使用大量内存。 - -### 示例: +## 🍃 Flyweight +The flyweight pattern is used to minimize memory usage or computational expenses by sharing as much as possible with other similar objects. +### Example ```swift -// 特指咖啡生成的对象会是享元 +// Instances of SpecialityCoffee will be the Flyweights struct SpecialityCoffee { let origin: String } @@ -1312,7 +1316,7 @@ protocol CoffeeSearching { func search(origin: String) -> SpecialityCoffee? } -// 菜单充当特制咖啡享元对象的工厂和缓存 +// Menu acts as a factory and cache for SpecialityCoffee flyweight objects final class Menu: CoffeeSearching { private var coffeeAvailable: [String: SpecialityCoffee] = [:] @@ -1346,7 +1350,7 @@ final class CoffeeShop { } ``` -### 用法 +### Usage ```swift let coffeeShop = CoffeeShop(menu: Menu()) @@ -1357,13 +1361,13 @@ coffeeShop.takeOrder(origin: "Buziraguhindwa, Burundi", table: 3) coffeeShop.serve() ``` -☔ 保护代理模式(Protection Proxy) +☔ Protection Proxy ------------------ -在代理模式中,创建一个类代表另一个底层类的功能。 -保护代理用于限制访问。 +The proxy pattern is used to provide a surrogate or placeholder object, which references an underlying object. +Protection proxy is restricting access. -### 示例: +### Example ```swift protocol DoorOpening { @@ -1401,7 +1405,7 @@ final class CurrentComputer: DoorOpening { } ``` -### 用法 +### Usage ```swift let computer = CurrentComputer() @@ -1413,13 +1417,13 @@ computer.authenticate(password: "pass") computer.open(doors: podBay) ``` -🍬 虚拟代理(Virtual Proxy) +🍬 Virtual Proxy ---------------- -在代理模式中,创建一个类代表另一个底层类的功能。 -虚拟代理用于对象的需时加载。 +The proxy pattern is used to provide a surrogate or placeholder object, which references an underlying object. +Virtual proxy is used for loading object on demand. -### 示例: +### Example ```swift protocol HEVSuitMedicalAid { @@ -1442,7 +1446,7 @@ final class HEVSuitHumanInterface: HEVSuitMedicalAid { } ``` -### 用法 +### Usage ```swift let humanInterface = HEVSuitHumanInterface() diff --git a/generate-playground-cn.sh b/generate-playground-cn.sh index 2bb3c19..933b1d0 100755 --- a/generate-playground-cn.sh +++ b/generate-playground-cn.sh @@ -18,7 +18,7 @@ move() { } playground() { - combineSwift source-cn/$1 $1.swift + combineSwiftCN source-cn/$1 $1.swift move $1 } @@ -39,7 +39,7 @@ combineMarkdown() { { rm $2 && awk '{gsub("```swift```", "", $0); print}' > $2; } < $2 - cat $2 >> README.md + cat $2 >> README-CN.md rm $2 } @@ -54,11 +54,11 @@ playground Structural zip -r -X Design-Patterns-CN.playground.zip ./Design-Patterns-CN.playground -echo "" > README.md +echo "" > README-CN.md readme Index -cat source-cn/contentsReadme.md >> README.md +cat source-cn/contentsReadme.md >> README-CN.md readme Behavioral readme Creational readme Structural -cat source-cn/footer.md >> README.md \ No newline at end of file +cat source-cn/footer.md >> README-CN.md \ No newline at end of file diff --git a/source-cn/Index/header.md b/source-cn/Index/header.md index 18f7f0c..1c42c6f 100644 --- a/source-cn/Index/header.md +++ b/source-cn/Index/header.md @@ -1,6 +1,8 @@ 设计模式(Swift 5.0 实现) -======================================== +====================== + +([Design-Patterns-CN.playground.zip](https://raw.githubusercontent.com/ochococo/Design-Patterns-In-Swift/master/Design-Patterns-CN.playground.zip)). 👷 源项目由 [@nsmeme](http://twitter.com/nsmeme) (Oktawian Chojnacki) 维护。 diff --git a/source-cn/Index/welcome.swift b/source-cn/Index/welcome.swift index a707971..8f396fe 100644 --- a/source-cn/Index/welcome.swift +++ b/source-cn/Index/welcome.swift @@ -1,2 +1,2 @@ -print("Welcome!") +print("您好!") diff --git a/source/Index/header.md b/source/Index/header.md index 9b34f8f..00db6cb 100644 --- a/source/Index/header.md +++ b/source/Index/header.md @@ -4,6 +4,10 @@ Design Patterns implemented in Swift 5.0 A short cheat-sheet with Xcode 10.2 Playground ([Design-Patterns.playground.zip](https://raw.githubusercontent.com/ochococo/Design-Patterns-In-Swift/master/Design-Patterns.playground.zip)). -👷 Project maintained by: [@nsmeme](http://twitter.com/nsmeme) (Oktawian Chojnacki) +### [🇨🇳中文版](https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/GENERATE-CN.md) + +👷 Project started by: [@nsmeme](http://twitter.com/nsmeme) (Oktawian Chojnacki) + +👷 中文版由 [@binglogo](https://twitter.com/binglogo) (棒棒彬) 整理翻译。 🚀 How to generate README, Playground and zip from source: [GENERATE.md](https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/GENERATE.md) From 10114a6924c3240ae52434095e25594c56472c24 Mon Sep 17 00:00:00 2001 From: Oktawian Chojnacki Date: Wed, 18 Mar 2020 10:11:35 +0100 Subject: [PATCH 29/66] Fix broken link to Chinese README. --- Design-Patterns-CN.playground.zip | Bin 25756 -> 25756 bytes Design-Patterns.playground.zip | Bin 160032 -> 160034 bytes .../Index.xcplaygroundpage/Contents.swift | 2 +- README.md | 2 +- source/Index/header.md | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Design-Patterns-CN.playground.zip b/Design-Patterns-CN.playground.zip index 628cc5603c913284c4215105e0bb435f57262610..fc26705619aaf88de8255ffda5fe0b4e375943d8 100644 GIT binary patch delta 237 zcmbPpl5x&SM&1B#W)?065V#mnw2}9tHZzc(%&7AlO#j!hXKo8Dn(U|>4Wc*C*FD1n zmdLZ(2bD0LoMNp8mh82T76l8w4hRDaxCGv2gsXa&EXU2vA_BCCg8^hzLohcd$f(VI zF-FW_GY`kdfoYWlf3U8HiPDoNCIo=lPZBD@atVobP`PX{?VnT$rcWoOfoYTE5~#fN MG0jU-t|T zSR&7AA5_A0a*DMYShCkTS`;k!Iv@-z;1YP75w7Z8vK%)viwMvn4hE1>4Z+-;Afq<- z#TYSz%{&|*2c}gL{K2{&CQ479m=FMFKS`(r%Oxb%LFKZ+w0}}1m_D792BuAtOQ7=7 NlaD1s^h%~Q0{|cxVrT#W diff --git a/Design-Patterns.playground.zip b/Design-Patterns.playground.zip index 583db0c50ee80b84a4e0fec97b0e852dd89145dd..6607c39ea0e5b3a81f38effe9ee909e8aa195bde 100644 GIT binary patch delta 700 zcmZ4Rh;z{+&W0_F`UT9bfko3_H8UDb-(SEeGrggJkqacWy|;idN*E>?0Tyy?VVnS# zgs892WP+&Y1F8===u-P}8W#h@0;TBzEsW~ZfwEfL`}-Mv>%fNG=Vc1!1*uzhqkQvi zMh1qk>Gpg~IrW}pW;4xZavJNmRcYBq?2QcMkE{Cd$WbsbK;Yxy6}#nr3)Xnvc(-Y} zoR86m6a7E`R_3d{_$F~%AWV&`O(swx)$y6DTG7IQ9!ISk>z=SYoVEYly7&)?YxvEs zvMKtpx}RU>q!1z$Tp{s#V}thVf1wg-e-sRNg(Mfat!2-DcTm6noa6tEI%RW3Hg4Ff zV6f+tu#(o|OI*U)Mk_D$m&(1cxN5lfAlKCL@Jinnh3C`$t$Cy!wC=U>wU;FcC1q8A z`mQ~{f8Wk0UjF<%+t?i$vM~W>r%Ft&-{bl%{oN^l!^`K%(>HFuJbAr=NtOQ*4zZmp zqvd43B$PPcoRfCJYm!pX_m27n6LS>B=luSCLi?mBPte}w6?^ob&v`yCUEf|XQYCcK zOBa11ozG_jljiKJb-X`c{(bC>eZP#V|D}BU{QG{t`hLFttVibU1@7SuQbG$`9%?M$ zEvc-WF-Oc)NX_keLTP4_V`EPsH{U)b-RlV_`U<6)qhgMY#WInL7&_Tp~l zuBYTZb1SyJ*2&u5#@6Py?8>S(u~O#T#hS@FvtzqwmF!|%ygP9I>*&%;Y5d8p6S?MY zWmj4(^XSs7)BhN^rwTCngs^}jc6wbRlhpL{DNMfL2$xS~`hp~Gm4Xo9^fGHU*t*kF#%4SO!U}9ik006T1F0TLp delta 703 zcmZ4Vh;zXs&W0_F`UT7%78Xu_)y!x#eSZO?%=Cr=MlO)h_TB=eE{ z5~7}~pHYnus5Ic9OYO<nr2gl%@x?Fse@nO2|yVpT@+uy}zH)w+?K`eO{(uUXbGT zEythVWMp87m~PLI65BTU;M7>jr#{x zMc{|3~J_{H~hY zo@>sYRp2nu{VUPgwZb6AxK(ZG*O{l7jtU+9z&mZlp5K>NE3-(N{z#XMpHvh(e?r`P z_Q{(sA1>cv_y6Cw#DBjEK0c~^zNoOk^QJ~<;ObiQ7=H7%=!ND{-#4%HK5_Hq$8d@4 zt%ql_Ca+vKOYSXiLXr0@p5+%h7A-qk|4-3X_m+d61%J7&F6&eSuPc2^a>BRFdA?3u z-(E3NC1uX4h*C+tPg^yN&fTB);QRCA)#A_A@6+jQ0%n@~mUuhF$P@d{e|LEFk>)g=JS+H@og#y*hBYyucpWt0(sbtFHYn zFezJc?dDG%%V#vlM;4y6pB|CIB(uF)fXN_)1r)c_8xonMre929@&(7aVk*-YByr<3 ri1_yAG^PM1B#Dn1PzlFOroU`pt&Rmu$!N)CV*yh(TdDvP0|Ns9Ch0{9 diff --git a/Design-Patterns.playground/Pages/Index.xcplaygroundpage/Contents.swift b/Design-Patterns.playground/Pages/Index.xcplaygroundpage/Contents.swift index 75f7a52..0bb8050 100644 --- a/Design-Patterns.playground/Pages/Index.xcplaygroundpage/Contents.swift +++ b/Design-Patterns.playground/Pages/Index.xcplaygroundpage/Contents.swift @@ -5,7 +5,7 @@ Design Patterns implemented in Swift 5.0 A short cheat-sheet with Xcode 10.2 Playground ([Design-Patterns.playground.zip](https://raw.githubusercontent.com/ochococo/Design-Patterns-In-Swift/master/Design-Patterns.playground.zip)). -### [🇨🇳中文版](https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/GENERATE-CN.md) +### [🇨🇳中文版](https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/README-CN.md) 👷 Project started by: [@nsmeme](http://twitter.com/nsmeme) (Oktawian Chojnacki) diff --git a/README.md b/README.md index 4790bae..6247c48 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Design Patterns implemented in Swift 5.0 A short cheat-sheet with Xcode 10.2 Playground ([Design-Patterns.playground.zip](https://raw.githubusercontent.com/ochococo/Design-Patterns-In-Swift/master/Design-Patterns.playground.zip)). -### [🇨🇳中文版](https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/GENERATE-CN.md) +### [🇨🇳中文版](https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/README-CN.md) 👷 Project started by: [@nsmeme](http://twitter.com/nsmeme) (Oktawian Chojnacki) diff --git a/source/Index/header.md b/source/Index/header.md index 00db6cb..1c5bc49 100644 --- a/source/Index/header.md +++ b/source/Index/header.md @@ -4,7 +4,7 @@ Design Patterns implemented in Swift 5.0 A short cheat-sheet with Xcode 10.2 Playground ([Design-Patterns.playground.zip](https://raw.githubusercontent.com/ochococo/Design-Patterns-In-Swift/master/Design-Patterns.playground.zip)). -### [🇨🇳中文版](https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/GENERATE-CN.md) +### [🇨🇳中文版](https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/README-CN.md) 👷 Project started by: [@nsmeme](http://twitter.com/nsmeme) (Oktawian Chojnacki) From c0daff5c3c04cfe9f7acb37219a1f00f64917633 Mon Sep 17 00:00:00 2001 From: Vinicius Leal Date: Sun, 2 Aug 2020 23:27:47 +0200 Subject: [PATCH 30/66] Add Template Method --- Design-Patterns.playground.zip | Bin 160034 -> 160258 bytes .../Contents.swift | 37 ++++++++++++++++ README.md | 41 ++++++++++++++++++ source/behavioral/template_method.swift | 37 ++++++++++++++++ 4 files changed, 115 insertions(+) create mode 100644 source/behavioral/template_method.swift diff --git a/Design-Patterns.playground.zip b/Design-Patterns.playground.zip index 6607c39ea0e5b3a81f38effe9ee909e8aa195bde..9f173d11255f2130c02426c8f515b6a643620fb7 100644 GIT binary patch delta 5839 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 F{{e(XB{l#6 diff --git a/Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift b/Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift index 898a6db..a12ced6 100644 --- a/Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift +++ b/Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift @@ -619,6 +619,43 @@ let isRachelAndroid = deckard.testIfAndroid(rachel) let gaff = BladeRunner(test: GeneticTest()) let isDeckardAndroid = gaff.testIfAndroid(rachel) /*: +📝 Template Method +----------- + + The template method patter defines the steps of an algorithm and allows the redefinition of one or more of these steps. In this way, the template method protects the algorithm, the order of execution and provides abstract methods that can be implemented by concrete types. + +### Example +*/ +protocol Garden { + func prepareSoil() + func plantSeeds() + func waterPlants() + func prepareGarden() +} + +extension Garden { + + func prepareGarden() { + func prepareSoil() + func plantSeeds() + func waterPlants() + } +} + +final class RoseGarden: Garden { + + func prepare() { + prepareGarden() + } +} + +/*: +### Usage +*/ + +let roseGarden = RoseGarden() +roseGarden.prepare() +/*: 🏃 Visitor ---------- diff --git a/README.md b/README.md index 6247c48..57b89d6 100644 --- a/README.md +++ b/README.md @@ -688,6 +688,47 @@ let gaff = BladeRunner(test: GeneticTest()) let isDeckardAndroid = gaff.testIfAndroid(rachel) ``` +📝 Template Method +----------- + + The template method patter defines the steps of an algorithm and allows the redefinition of one or more of these steps. In this way, the template method protects the algorithm, the order of execution and provides abstract methods that can be implemented by concrete types. + +### Example + +```swift +protocol Garden { + func prepareSoil() + func plantSeeds() + func waterPlants() + func prepareGarden() +} + +extension Garden { + + func prepareGarden() { + func prepareSoil() + func plantSeeds() + func waterPlants() + } +} + +final class RoseGarden: Garden { + + func prepare() { + prepareGarden() + } +} + +``` + +### Usage + +```swift + +let roseGarden = RoseGarden() +roseGarden.prepare() +``` + 🏃 Visitor ---------- diff --git a/source/behavioral/template_method.swift b/source/behavioral/template_method.swift new file mode 100644 index 0000000..e9b0c2b --- /dev/null +++ b/source/behavioral/template_method.swift @@ -0,0 +1,37 @@ +/*: +📝 Template Method +----------- + + The template method patter defines the steps of an algorithm and allows the redefinition of one or more of these steps. In this way, the template method protects the algorithm, the order of execution and provides abstract methods that can be implemented by concrete types. + +### Example +*/ +protocol Garden { + func prepareSoil() + func plantSeeds() + func waterPlants() + func prepareGarden() +} + +extension Garden { + + func prepareGarden() { + func prepareSoil() + func plantSeeds() + func waterPlants() + } +} + +final class RoseGarden: Garden { + + func prepare() { + prepareGarden() + } +} + +/*: +### Usage +*/ + +let roseGarden = RoseGarden() +roseGarden.prepare() From fe4e9daf69834c7cb51e236828e6c38e35102110 Mon Sep 17 00:00:00 2001 From: Vinicius Leal Date: Sun, 2 Aug 2020 23:34:14 +0200 Subject: [PATCH 31/66] Fix typo --- Design-Patterns.playground.zip | Bin 160258 -> 160257 bytes .../Contents.swift | 2 +- README.md | 2 +- source/behavioral/template_method.swift | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Design-Patterns.playground.zip b/Design-Patterns.playground.zip index 9f173d11255f2130c02426c8f515b6a643620fb7..3c49b3ecb6639d368309131d2b7dcaae94726b2b 100644 GIT binary patch delta 5590 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 delta 5559 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 Date: Mon, 3 Aug 2020 00:59:58 +0200 Subject: [PATCH 32/66] Update example --- Design-Patterns.playground.zip | Bin 160257 -> 160280 bytes .../Contents.swift | 12 ++++++++++++ README.md | 12 ++++++++++++ source/behavioral/template_method.swift | 12 ++++++++++++ 4 files changed, 36 insertions(+) diff --git a/Design-Patterns.playground.zip b/Design-Patterns.playground.zip index 3c49b3ecb6639d368309131d2b7dcaae94726b2b..94ce1259c39a866e388485a268ed65a7484550ae 100644 GIT binary patch delta 5759 zcmZ8lWmr_}8f7*mFhhfMmy~o$D&Go>KYD2OBEdh7wz{$f{mU85kbE_LKJHiLB(#rugD`e z&;xYn?WN}xNB}AO6re%AfP!%GZy{}2-G}(xBxq>`UY4e9fxpe#`u>AiU+Sh7rOnlG7_>}lf6 zfnsVlVN6&cvtSYq3ZIS_z9v39M9oWO!qRoZ{y3|-SeeUUp2vma$#}Y9tZf&IhO!vb52zl*#&>3*jYO z(fhdlSu3pl1-?@nrh3m2PY>oD44na`&{u|(sMZYqR_T4#`@Z#INS0jn>PIxgJ}=r$ zEfaf|^piI@xPttKld$(lyhTK5G9M!E=7b{pzg}HF*1^uE|SC z1E!z8m*C;XJwM)uNr5VGGHgkBDT?8HTH(|Q1bc?r18&hOF_Z_}NMm8L46$CDl)@C< zt@||_9klU)bC8tC;=olxEA4XQ=+1&#NvI4DmqAenTbBwsteY@Y`)C85!H=TD(ql>2 zLrIsCnc|uhoTx+4j$%m}-hx|H<7roYZ{o?(9=@hA8PaSf zjBm)gKqnQW=rD$v(XgKPkE;y~^=1dC;VZ#c28n_FnSjflg6y)Rjj7=d^hz4EHIDp+ zh5~ihjTbm~xEQ=1#bGfHTC>O!c^XT7Yd=Yz-~UrNQVb;WeUeET{1aOQ>Z2 z$egfWVZ0>GuZ+4q!C$SQq#yL9+p?%H`gt8SJU?E(G@Sgfi>$mTrFPTb@-9?fdavKFki;>#%OR|y8k5XGO$9c6h*lPT^v-5#88-Al>aV(#R4>cTwgwcucb+rcKW?*qe%bkf_X?3zD zn-%?#M+eP6yr@`RcLn#QK7_C$k@K>psu>-(iTl0mHU)*e?1c><50@{;l71+l z(nJW$8QyASjc1ci0bye@>=ab&ZN{@ zu;xbFbarELuf2m$PA+8CCwktQ*wR=7Z@B8_?uGJWnATgE^!Wun0Re$_5;^x!x5_84 z*F=)*gMe)#w}5gGb{VY*s&Q3_O7q_G>W4QlP)}w$p_B8&sHVkNyw_t?QYw%yi<jBIWXHJ02QR=wdAhLR+HmR9<7Z&h7zBgk3SLHG4@8r^Cf zJXbE~VaxDdDrMV!81aw3Gd?=?mmf@)s-^|D#j@|~-YZ3sjivw4UO5QhviwP^s z*q7Zob(!@2;{fF#v@3R&w@ak+i^6Vf~u5VYpvFh_U3)7=I z!|0`P=P~63*jkfGF$;w_NQs%V7h`6h*1l z6Nci6^3qkh2pIXH(7SPVqWAFzaY>Ua;bfSQ;)v{spP>2p!jTFT=V-1W5r$1`SnW4z z-BCpm=IZ98E=ZSu*L3X8%J(sm$po;1@`mwu5O{!nwN6VJ7--58kq=VDX^$0KFzZ~ zQ;jLk(69*dYv2Ds)UdS&zNTC&)Ra)WImY&2^YOHPVzQNFlq$l#2NRs*+4=z#%+oyY zy@=Rk9$99A7lrbBLBpvt?yZf~p||q6Lg3Fma9Ex%$j*_^ew-WH68SXU+t&I+WsaQN zvQJl;p_{smUsiP=d%AjHd?Ga;Y;J>pQ6omc^KqHfBSK%(4TedZ=fbd96?;JavII*{db0Irk<=Nd62@-GEkN!~}##m77a(0*5%8b?;bP(i_^w){Eq+bW~Q7{N)25 z?zd9DnKatC5z+VkUf?)~(b4vn>LV^A)M~tyqN=Ew3P=4Y5azgiH-7V}g*QKjuF0er z=81Y>efQh^A^cQkZk&E%^a#}82)cunh0S|ZHPDCoQ9Vk3^ia*}nW)X?`kH~zcG=$6ydM`(x*6Shc*0NuT_wMx>5%F6m*8NmctqMOG~7IFd~Ng<^7{Up!yIHgnP+16CldU)-DZsR(2DseawUq}i` z!ls*1LpJP7@e&teYxptv2r+Ep&Bp&w_}R%t*-CmAa^m0Iql1KlID&6Yq$Sh6L1ML{)=bzGah=BsFDuXIWk7d0A4sf}Xtj&UBXmSuwNdFIyWq z4W-`2__HADLVBM*_vMSM4^+J1RdM$8hR9hVC)RiE!U~_)gdgo%8jA9g9IN}? z#WAGrlEcVbXAGwEiO6ogLW_x&3k4^HUZXceBs*Sm3pLrH1lELjdk1I}YI`WG6f>m4 zm(pPm?mzR6b7BaC`$vg>V^b(p*PwQ9%!9b98p&(qscUd*kI1)p_=Zm-M{_d85*2cM zjqg}JKPE`FO}*3`K!$nS+gmTv?W|p^W9D1&)Is>V%3O!M_hkZ(#y=U$Ec9Fi)~*aS zzri&VlR^Na9 zyS~@AE@J=rz8n3|LO57#?Y)GtJrLIwOUOf0bJ+=u8Aq{PfWqBgi4LrY?WjX4i z(oDW0!MZ3=MLLh=K{WV2mOOKY6a+d}1RsMf z0gC+fI@?Xr#h6RCdcH&JwR6s+mGDxvNW5EUxrjo35sVdvSf)zhZCotC=V}y5FOD9H>DdN#Y(U; zW?rox6wMzaeYWQIP-Q3~9XjW@dr)?TAqPr;EWdP6W#akCZL?jmMsHqo` zJ60sP^ks1F(c?JDhP~kKd3K@u;;vcq3D{Y$476b6)}IhQ4E(tcCXMHpAa~2!W7la| zj(NzOKQ(!O8C{fXYEi%fOmF^$!)vR<_98MK@dZ>EhIy&nOIKZagv-OC&m8a!^OK44 zU${7*w`U^B)8BpSnQ#_bX7U;?c`bEJ=w*4df@wJU;vk<@Z@)jDH>P=hW3R}FuXpz7 zsXA8{&-SF!01gfhXCm>(UKf!<%mMTD5g+%jf{8=xKB19#h6|bWVz5snfuA;maT>}E z?tG>=x;9M>i)##p`-d~juxsLvDjd!(`txO-+lD36b(ZuYORZ@Ke+@`X;l$$oY(j|# z%=QJD+yoO3G#?zxTG)40#B7pmA5Euenl-O`ICEch%3ob ztlKKbVT9fhc70a&Bn(!5Dm3FsD!YW0aB9{^i8=PW8#}u_SD_MHSlGvV*n{Iq-|;DDLbvzsH7Lh7=r7 z#>-^~#h6+N+cC3D4`wqpimp>^@ft)ZLu9i8ZVKY&>Tc>?Wq;VlTl?rTWahUnaAt_s z%W3XRL1=1Tlz9KO$ZV$-hKJL$!l?8Wnh__=Fq~4D*DWG z-Lk)u+o!G3KFvMJJEm5thGFMZn6UnV*>;lS)?5C|^fGOJ_LzcFar6Ciw82xnho2_$^i&$* z_~*(%g=-I zULjkx0a~P17zpbxbI>vaM1oX#27v#Q4vhYX#l)?p3IgcRNpB6uJ7~WP5>P+oq>Gs1ZX3(oNpT^-69}GWTg|34)~P+4#*&5 zoB=7|+utvZ<+lP3*xb$~>jJO<8!dlvDr^88WVs6<0vNUa7sBfb=z+o!Zh+2T<=0n0 zqO&JMt12O#p%)5bT zVHsM(A`4X{&kLrjTV*uqJ@~O9R)7h7x3{`v%!oj%%`hwIu=7I9RVZkwCH|TP7S4CT zkrTR0U$+(um7yoYJCkEbOp~G(%Vr&5H<~cwb}(d;|BF>IyS+q#5wSyEPHr(3t@moG z)lhYyiy;%ua=2a*1~(&D2EGwSlxtqW>mPGeKn956HK;hXbV>EPB6?9+ep zVO5XQG0Ze2Iek3*CK5zF4aG}On&2A1#KF)~!+sv2N1oG}VbdwGkNMEA1&(CO_ilSa zHC`9mO=*_E@1HFOyZou;<=y)=o;LZ^_cGE||D!#}*3^mLVtvM0C#Y1*bs6mjCb9`R zYa_ExVloSouGq{om*pHtD>8)2Br{1hMZKpv9lc8>fX)0dc*#q6W;y#aSQV42K@E{kzG{-#>{&9Co}(P^OYFQE znrt3^5V{X!Nbx~Gij3Tm!b8~+_R(!RWU&h6jEWd{ie=iJrlL`5h8tk9<~~v0^=n~? z;mT$DHpE=oDP#@tG_4eQG7&5tau9~d2p`dG$I!23xQls4wttwuw4xHCf^*5)!jZhb zf0BwYf9|7ZsC7tX?;lPa-8*7rRF~|9(X(P)hC71AV-77zuT|c!}6$)mo9C6P1=}N=_aH)(27eJog3SCD4+h zq%WDVC74h7Q+UG1)jQGHPsRw8w8+aVHX$t}%%U4lc;4p|1$;OwCKqyk!bB(RcAS~; z&DvI4^6atDR>0P&#2Ytw$u{&LSf(r9!kMo_?s{(!9C^#5s#qK8}SZ zbOVhpiswX^y4+I+TSZDAl>5MeU;mI(4j_?6PH8Wx!(QXW6@+0wyW3Ob*vgFARQmv; zJ25cj??vtG5Tb0vV&?{NFSc#MzK6zjMm*CeLHL=Wgf_w=g@90sAI4Qa|M{Gjjmx?C zi7ztIc!4JcRWTsry|D6vMf(dVD!`9sI~uEI7i=F@hz4bYUC2a>zABFDq}%S2@4xQM zwR$FL_3er#iUvMUigo2m(QJADfZ)!Hg&T7_Yyh&$z#QqEc8{dBxih#uV$rT=IhQ4h z@6hv*Ktmh+*p zi|8NT`Oqn;fg9d@deK31o-2*qrh}lxWcjrAyGx^9;x9SlMl6pm8Ju)a`n|mrs9P!u zQBT=Zgonxr1&-dayBp3YTdGuBS!_q*0b0ih6dKmiaT=(Z<%GrI2i&**p|OrDe2IoG z;(WGdMsLBPoVvxNpgeh@PthgeD=@*WoIKJ_%;=`9#k2ttuVs8>8%#_I2H*6-W_5oeCOvHK~)why_xd;InOut>(d;MWw~_A>+u~O zj3)>@h=sut%&;FlF*kcDy!iNxBqTy1Z$GQb9b|2k5kf9tx$&=$u}{vvCBM6If0U8S z0MXAuqy?<8G5QR@!R+@jC_tXm7>YVc`S#iKXKQu!xx<9flSBpRr^j9p`?uqooEHlO zyrzh5f0LSTF6CG`(_a{cT6}T&+QsZy)crOh;js3?*bGfe;~nF5lQ0ASAnrPLDnr85 zz}BZPci)er#>4h}Z{S88rSu7%H;QH4Ygc~!IIAvU^S0fUs}apA@XB!A1jh=ju)cTY z2`AB0?HVw5l2T8>%V%9{d-TVkW$d~u#;&w;Bej?8aZG9>k1$6*-**^Dx24;n8qz!w zN=f(I{+f#siMp9S;H(Nu@@z$Ss=N+zuk&!R#Hr)Uk|A>G!F=VIx_x@&$co1i(fIw* z8u%|9d0NJo4>t>=-`%rHM9V|da`oZtQ|x%KKa#5ki+L`xD(#PY zD&cV)KWz(Yne_8DOWi3Z@cn4LKo)H6U0&@g4wr+`jaK>$A6@umw#Z>(&2vb;lG+Oo zrg**s6W4XJ{D2CjmU*><(xP*7$RVK)A5ZnH!-k|PO0aG2UK{SBwrKv39|l-`N7Uf( zmnD#k#H>NY_)*LsH~J;$1U-?KlS9QVhe zF1Y#_$mTh9;+$pED7ZV*Y|3Y+kI9tuRT8Sgxxj2DBd=!P%WOGvQiH^c#w4==MCq&y;8n9gC%J>1>?IOt_NTWYl2|N5ADkaTe1zZb+&$=edtj8pW ztGf4@9$CX|%}iU~Dk;to6)@yu8D#+j2Ew=KDfg{Jk4@W~S*qKoTzfjQbUb$2>eEdu z_b|4w1WzA+hwvdzKGY!ytmX*2c(VQH?smCx>wdloT+EmdlS6ezkQ(!UYqgh8b_8OG zkYQMIuBW(jlX(t(`Fdtcykag9CFi0tFo0((*%SpkM;As?XMN`7I#F;+n}%`j@otlO zX8>;(sXPZSqrNkKx@Jl$e$M0V78yH2Vrf4SZrFsDeq$&)Trq=s%S@+@L&g1WJX0Ucz~s1Xd*G2TciXM+d+*8zK%LgR4w|k?T^|(X zWVwH?EhSqVe9{=n+z9wm)zgnXZRwdN0t#7 zUbSm5R&rJR$YWS6{MuCp?i*6lI})CHq0Q(^k8!7Lj#7qfY6d;m9+n-?b-BQ^_#uWn z(p*W9G84F9S>if;%U+A#i=zzW%Z}0))f`Jvq|WGb7L|2)NIPj;IzRL0cC(+6`Hosw zn-tvSL6@PdnsVE6w0(kx*fg{yqO=y%+8?msc#%L@vPF)6iY2&m>}VS_H%%1g#I|#ALcPMi(Ch5Wk*kd$0Dl>o);sC7YOh@s+b%^aaM%S(!W4oH79T- zm2d7J1jQtA>rh~so>2hM&#se3{{22lsW~@a%z5!&GYCbpO%ZxvicL=&&Q;E#ue9}5B}RVEuM*9G2^RhpV@WGGdh9T1)>@TD zC&M$Yd4kopGJXQGo_8KO1a+};D!_ajt9e(i@KAa!X66&gJpr@M^S+T$$SDOL2i^+@ zuD()kT4%8-vUH<47m^+vUoo2S#;_yi#z|&FXBxXT8<(;zr9Mb${rOl#d;|L4=3_maHaduHU>kXDz#rwNbk^S%*D3rSuod2p@>&c;z$@8@byIz z{94Wkc9*D}ZwssH4EpmNMl*S8^SjN41sP%fae7fj-{vI}k@=Qhj8eDMsejJk+Dbmuk;h?%)CoT9$n4;JQ1 zPeh-^jz+@K9!1?imCl>gH-ZeF`TEHHwX>qO^yR5Jc-njx&2wQBaK^ql5;PM}J(GX!)C^)#dRuq;X!{o&Y7sRc zv4bUj^2_gBB#k*$*~QQDEt!Dh`F+yv_kWKJWjkaGlQwb3oPc-@VwO_g!l>~)9aSPiDM8B|+n>a|hbgVb+%19+K4*R!f6rJm z>J?&EL!VGOyYEmky{$EQf*6B;pRy!RCZ6c$pfm0-L}NS*MSslz>FcE-lM{r};)}w> zc@}+~Dtp^1>7OKyC1zb!Ib1dD0uqPQd{T}1#j!c^AQM`so53u$!0G%=Y=31I{%TE0 zLtdu=LJciX(q?l@+F-hW%qio3bP}XiVId(U?EUw7yXutNA8qrjM%fMcZb?;0Y0DPw zw2Q^$U%L{s%HVh`Jw2oEMh?Cgs5}@oNvJ@9Wz*aSOR&`1$V=)>f_Kj>x&9h&D#E2q z#FMQ5mZ-0-64W5Ssvpxn7>lIcds`Oj`zfg4<8T4IfK0C|@x!->A797w<$l0;$Cf%u zz9g?}W;Q$4SE=*Zj?2Hflq^P@Rxue~gejwVtV3i<|HT?+xcP?8>@d zd7-Uyk6tAnPbUq0eZCy>)*AI>Qk{H1+1mx0SYoR4uJic3bMRE-WIz1U&cV)LPbj+M zfG;p_jsGV)A;jG5=yWY9UzmD9P$*+d^!gsW$wwhOjiH75ycV>crg07c)Wv z9cAC4>$^MPb=`TWh0C!*tp#cq=CAFIj?xVuAb5+YUH5xV26$BgxO3jPn)PIb*Lez$ zTDHqgu1JYPX6wixB+7x$%kBABSiEP86BcI(GhDi3?irh)_hujxI{8GK*_v(3+uvGt zvbl0^k(T>CYA~Y}W@V}^l2Tgdn0HFRGj1F%+*{4Iqstw34J7(j(JCqla|>Yo>9BZB z>}A4D6e6*H(E!E6^TlR9!IuwF%O3eeezxN(et$HGw_DNfVEd4{RDYd7w@8Sy%A1@~yP4s{*W3zX2OFguiYYVU-`>1EQOA#;tjUoX z5C*zz)Xv8g+=y~}1xBXJU}I<5a+CyQgpHjO;xistcn%1OdGzhFhfVp#uC%6=+j6Gi z9UXbx;-N0WdS)6NcqO(O;i4YjG)Md07GJS$^*{ zPD`@rcUnxAY#88;$G!a@`&^@?p_fuD%9n}AM9?3)JmSS%_6dwxrF zL9|&XYAlR|P{2kV1Di`3^MQky`v<-|{_T{r1EY^8%Tuwo7`%4MrfP?!TSU~VSeGlE zIrqD*FKzGtTn+1g?*bcChKe7#Jn4?GjE1rM@%T_M4gEg5~*CLKMaDek={uX&etPpOqj8IyPjMAc%4{o+c& z;q2MX^;LV4Z|ll!Zi?4J$!S$)zBB{x4>V-YQI*m5JDZXbTv&cJpZVUSjYHeUHYR#L zLa)b9jeG80_G$;DUiXu8_!nU*cWhTGM|UJeM1-~1TSJ&{-uF@uV>;H^K3YRk#0q*i zRamHj^>JV8CW}Mu@^&fQu6=07NS)!K8@r7t0v~SKlZTvU+BcSwUG==5IIS{#%3>u? z1#kmG5MNv0TES-bSTVo1&?p8AtNII@Z)E(~>lsZCxrWLF(+KiK-SiDtcAs!7fyoC6 z*1Y??UoZ4|i>_%rvJ-m5QT#h!2faaA`(C>zuoK! zpi3~utt_XBl!^uMAom@Bhsc~*kYU4G258UY&M#5!x0d(&l`M@(kEC@2VIfTjfP24X zyWcDi2mlG-x47p-1jzj|8tRCELhau!6B|I~ci}sB041`|22lOY`j6CyWUvKZ0@u%x zxjF##ANpHWQ1tH{pf%!OAvHUI?RUukmJYZF|L+hL@>VLmgS=J+@R56V01ZGH`+os$ z5um%s8{1oe^RrvP>^}f(Bs300iA-<@z{u%eG2XbplYhs^|HZCqe+$_Ce}KQ)|M~oq z_`g}OZW~YYy8zv<&UVTMA0TeE(j10cx$}S947yzl!Y~v5E9YOw`g2){wg3fyk?{}c z*UcFKT^Yy~CqNPz?Ffhg4>SMX5F^Q*00odaa@h&cMrJzR9=_8FpaFgS<;VcWJN_VB zodHQey7SLQ%mpw3Tvz{W)Yd@6$ZZ#Z16cUS14X*J+%hG*-gaXAuRlPUQxF+4+wr!8 z#BR3*q>wyrKqh)91W48dQ6a}5fEbd^9l)pm@4-St6Z(6~2+?+=tM2^4|1)cGw@JTS Yn&l2qqGJ>ME57Is2w=$(0k;hQ1IpxO5&!@I diff --git a/Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift b/Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift index a286c68..3d44f0d 100644 --- a/Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift +++ b/Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift @@ -647,6 +647,18 @@ final class RoseGarden: Garden { func prepare() { prepareGarden() } + + func prepareSoil() { + // Implementation + } + + func plantSeeds() { + // Implementation + } + + func waterPlants() { + // Implementation + } } /*: diff --git a/README.md b/README.md index f52b50a..c90be90 100644 --- a/README.md +++ b/README.md @@ -717,6 +717,18 @@ final class RoseGarden: Garden { func prepare() { prepareGarden() } + + func prepareSoil() { + // Implementation + } + + func plantSeeds() { + // Implementation + } + + func waterPlants() { + // Implementation + } } ``` diff --git a/source/behavioral/template_method.swift b/source/behavioral/template_method.swift index c9fd49c..e177a65 100644 --- a/source/behavioral/template_method.swift +++ b/source/behavioral/template_method.swift @@ -27,6 +27,18 @@ final class RoseGarden: Garden { func prepare() { prepareGarden() } + + func prepareSoil() { + // Implementation + } + + func plantSeeds() { + // Implementation + } + + func waterPlants() { + // Implementation + } } /*: From fc21337b233b14da47fade4bf5d0073490cbe1dd Mon Sep 17 00:00:00 2001 From: David Orriss Jr Date: Fri, 4 Sep 2020 11:06:15 -0700 Subject: [PATCH 33/66] fix compiler error for template pattern with swift 5.2 --- .../Pages/Behavioral.xcplaygroundpage/Contents.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift b/Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift index 3d44f0d..49f42b3 100644 --- a/Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift +++ b/Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift @@ -636,9 +636,9 @@ protocol Garden { extension Garden { func prepareGarden() { - func prepareSoil() - func plantSeeds() - func waterPlants() + func prepareSoil() {} + func plantSeeds() {} + func waterPlants() {} } } From 20501f22eb6e5f5efbbee44f0c68d2999667c52a Mon Sep 17 00:00:00 2001 From: David Orriss Jr Date: Fri, 4 Sep 2020 11:51:08 -0700 Subject: [PATCH 34/66] fix implementation of template pattern --- .../Pages/Behavioral.xcplaygroundpage/Contents.swift | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift b/Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift index 49f42b3..c8d0473 100644 --- a/Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift +++ b/Design-Patterns.playground/Pages/Behavioral.xcplaygroundpage/Contents.swift @@ -636,9 +636,9 @@ protocol Garden { extension Garden { func prepareGarden() { - func prepareSoil() {} - func plantSeeds() {} - func waterPlants() {} + prepareSoil() + plantSeeds() + waterPlants() } } @@ -649,15 +649,15 @@ final class RoseGarden: Garden { } func prepareSoil() { - // Implementation + print("prepareSoil for Rose Garden") } func plantSeeds() { - // Implementation + print("Plant Seeds for Rose Garden") } func waterPlants() { - // Implementation + print("Water the Rose Garden") } } From 10c2196278d9ef48e265b3150853568925260a98 Mon Sep 17 00:00:00 2001 From: David Orriss Jr Date: Fri, 4 Sep 2020 12:57:06 -0700 Subject: [PATCH 35/66] cleanups of compile errors and subtle\n changes to the call structure so progammers see what the \n template pattern implemenation looks like at runtime --- Design-Patterns.playground.zip | Bin 160280 -> 170902 bytes .../Contents.swift | 12 ++++++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Design-Patterns.playground.zip b/Design-Patterns.playground.zip index 94ce1259c39a866e388485a268ed65a7484550ae..bbc75e2c6c2bab5b26bf521fec27e524290f1f54 100644 GIT binary patch delta 10804 zcmZ{~1yCJPv#!m?-CZ^s++8*Vf(3`*?(Q0b4GuwqyE`Pf6Ck)dJ4kQ~!GmlF&drze zpYz{ax9&`hbobk9&8nKI>9y*~+(S!mL&s8ALO?`^`_HCr#E^s~i17CkBG)1Zs^dib zp~IljcE<@K0U^r6$tY!PhlAKM>T5xCZRXsdCdhxqNu5E<@c+rmxN-$S5VXx0GPc4& zycx4L@RS+BZXopkxZ2{~Kh6T?7!v5Q^#=l4ZcS?~$qRpUo10iP^r|6Q}; z!1KeC{r4z!P5$?szoX8e^cD`z z^Z(XiI>EC6r-mN_G#6Sop!O^L&MAVW^v)}#9K^|tD)ao|RRro;_7m!n_$#T%E2Ru9 z>c~G(WRQt|fwCqlUeLw87?ViWN?ugDJiyG@SGWDCR};2-xj=PAO9>|mlEM~Zr7g%U$O!%gK7%%No11+24aa1-J~xF=m{2d}GSyKLUUnhXO=!0{Sr;C5XxKKc zFd=r>z_za*LPf9rEJDtf*D|JUuh_Qnxr;A=(?zm@@;eHr7iAm$7S{-Eskfz`$R%`j z%jcFffKmcf5I)nFv6XYqaVrQx-3*D^iaJMpM13X*3Mp3SkCE~ym26u@vXNjq;<|-!tMW)3L_t0HdrSJ3TOu@JH|5qc03C?z8Q$FTyfu8JdIrCQ z0z(<+J?GSj1ZW=_#uy^JUR5!~S1O2(F|I3cHY5hTdxMb3JqVu#6d4B|o3k+UX!_Ucd4!x+MzRAVSaMkiU@ivEX;U`pWLt4rPw5nYNV z^e;3IW5;_~9>HA-8?+;1{(Fdbak;dniCkm)9{G>G5$^b$xv^WNMhr~5#qD;gLqncu zMqt~W$=ryEU)4q++g(2opIU%qDTi$j*<+vsZ%wZ@CZ|_KghVLKQ`cdA3JXhKiZB|P zM-qD{*a0@{@x*T%TNm@R+Da{N??_H5Valc+tQW)Vf}}Vbfe$vY_iHgSG;)|0%EXBA z9u9r9$ouim0!p+;LVO(K6k%g&5~T6cRs87C(O6yT)jT3LwX|31o(}jrWK-n10B-vX zi6D>GV5>yc7P+dh)-(gKFAsOafWLJQ(xw}Tuw2?t-MN?X8 z`hnAjq2YH;MeV(ru3vz3+X#lnIa%!Ac2TaW6Th<8wkS_8mohrnG|3S=7A{?=Z1Lr_ za5$(BVRzytD92#QYW%284GuL+V+_Yf%&FRvY)C_(PC|uwqSQo#sXl7KC`iMP*Tl-hH+}RxQ-`!v6VV!6RFrLzn120CSbf1+cG)?JjezFByWK z)TK{kMgF|b&yuF%Gt#82E;Fd@JQLNrH^$-wl!}%PnQa^TUyuLHWr;z>B3T)fw{|fl zxEk6j0WYN)>;SNi^7cAfty!hq`JXTqGaQ-qhL8EBFpunZu+}`owlmSI z64p13P7W(il)%3a_DCKFY&hbJq_ z4+%2c8x8g!Yeh4lVkYg5rt%`4MCD{VnL9prIgWV)0>G0?x#X=UB0s#)d2l(ayV%#P zoCG|syl)rM6G}#t4G@>8wz9PAYzZ5?yZYW6EY^JlzPhUAlVA(-?ApVn=Gp;ep^!U* zsB|3r8w?4fgKJR(!FpRlWm{CdcA`!WIE*hp-HSe*8aSD$C?{;eVtbuwZ28)e*pZcb z-_>KTDFRLQLVgHSMeFtnQ(Hdulxv_f#P=bcRi9Q4%|x?R%b?*%+;LSG-$k$c$^Ejs z1*ThvYT2Ptl(JmH2&>6M`HZb!7d*V}Mrks7q}x1t+B$|ePpr$&{JJ?g;#0)27B2UW zoB!B~C5p&)G=-2Y>96)J)G;+o{&MuW4~^7ATLi*#Rm_O=uoi<`%%~QiMh=B?*==ae z@a8IlAyeOFu6}>5V?(4$doU%BDOsuyyVQv303d1p7J%@g>{S^-BY~VV=yMaogBE zn}^;_OV)DcT8j0?IsN^5?g$b5Ck&mV`oAtjvuGHDv53E-Xm6tVAT0RR$7U~u$ydor z0)W&dvpj--&l}T`TD8y$$?31&pwnNIJTP?%M5FPhWxq;i9ZfM-ag2PNj{zaXvoNy( ziSuM;n%gby^91#or)FFK8HBB=X>pv;-8cODSlB#l)FAn+v;-cCKNjg{Di7RBf7anQ zEF1O^ZgS8h;F;`S6TgXBcBQ3y>q_XQiU(loKxBf?Y)nUq%Ut?~9A!tj?9IhywdsZF zS0@p=^7k2u>0-!GMY02?SBldW3*Zh8tJw^x7hjRWYKi}B8pIuw@iH;h6ljlZ_)OeL#g{@R|>FkIfJZ7p6vI}KLd2O z;?PvtR$S*>tVg_DTzCWGY+Q@c2u8wT6cSXq-qBf9GOF(qbjagk9IxWS#++D+@O?s9 zNpT3w=#-1457b5Duq)^f-Wq(1kkS*%9DjbsE9bMooe5%Hb_EPr&O;qKE!kuVdSGU25;XP3<9L{_RfPX-NS_zcqy`d3RL$-EnIc43Y~Le5`HkO z94q%fPH%fODJy0&;U<~ka0gK>#4L5p)_?kh&y(HXr32~+(-DwnGc>Uax%0xLT1Cf@ z#Hz7y8>mhb?*4J;Om>F*mJs@V39QHT9jUAS6f3m&zSknL3GXK2$&8l0co#VE6%A2c zLsc?kIl)1hbrAh1dawuQXm=?Z_-4&hjiv5_UnKTeJinJ%!TjbjLo|ScD4&=3+9-}Q z9=92F+1*I8s9#d6Dt!d`Y@Ce9Y_4gT7Lpp~@PWjpgf6P5+yw3y`Y(3CEI^j3Qw&?a zH>sXdr&qE3j9HjGH^kDMh!PN5+^((qgL=#@NYmVZ=uElFjLPD3o2&iCw+8D#UqHMR zv!+5|n{bxp`!#2ZAV@WQ!401hBT`BZu~XQVCtH2@GNU~}1?v;Bd)f%Mr+`i~zX;o- zGLOMXCKY{Hs` z|FZ2Qj4~Z@wWZ=FQJNTqVTT}nDR)#3UXiKLl-vmiTa%=KOBTl`Sb(NA_Z4ykP&-qb{mz+JQ&fQ_~ zd-)SD{PyVkcy)8ZnH(ng!Ow7dqeZ@L*tMqewz09_KrYo*;C%qr){k{s*g)oDZHL`9 z+i|=-;FWJS1hZ)cqWtr`RqK}Y4JU6-2@~4NyofQP-vm}v%UF%Op^)}~&cZvlT>J>~ z)L0gH_0IONX#J=Oi%Fb@;ZIFr-DqSMBcC4}bGNGe80tZq*Q2H#tAE zv*IbHA=36WnD#5t*k%}kX8P;4md+`Bv4b#r!Zru4&H)r(&@(Dmf5FzwImsjV;*cR4-t3BzhU386k zFf}`Be0<(WMJ<$T&mD2<_1@VmeA$>vrox9B)ebNnHnSy;-MA(Qv-ymr#h6JMG8NXoZZm?)18KOq*0vS8eqQG(p8ap)ND5Q!7t)wK~1b0K~_F=AYC=TZp|Oe0&L zC;Vd4?AVw8BN>v4B!Py&-)Vzt!E!LA6VS6b%k(23!a@2oQWc6sS)5BtZW$QzMz3BH zcNE&`b+)?Sp({bX1>+VxBGTvdkQ(sgPm_?9M@n;$nPOLxblH&fVvfp-I`HE+Wz(X%`K5!`2hTMJoL)j-QPyM6 zr2jO1c{n_VVfh7vOMlNwpByFDTL4vkzIv<3iGBrN7Daw+FU)u?+#l;>dw56nzH87m zgDq@dA3KI8D~xNehbOLWLe(ioefV{is_-5~&Fs4?YNvl$W#&9rbd&3id#WhV2Iiiv zw3?6sb8Lm4`=;NrX_TRLI@R%G(iF}FE9hD^c6=*uHcMSw`n_PNN+O%(hd`S5Nkkxl z<0`RNJyd+iv@ZHZ2C9Z3LuN~eODUaD!jzfGG^crB55rsu%a@%&OQjK>q`%z%cq%~` z{Jv10el_tl0m*>b?4kba*7A+uJ*~K++B`k%?;pq|n#TK5MI%=NQJ7Yg^Q^Udb~eUD z=HZ|dCf>R`%XXlB(~QI^1w4FN`BjB!*V_tZ_v`wcNo#JFAQXN39CKtSegYpNhaxO=>HbH(zbmeRg zCrbixsn^BqAB=|a4Q*%E*48xgkryX2*v^qam>x*}cgNyW>~udDMFHDAzdRMN=^6XB z`xz0z@%Y-;%dA?_mozLYAJ;Rt*1*7y)BU-b&xc)Yvi^CJ)D4A`J8Nm*W@A**ZNBQH z2wxK3%do3@8*Crb>amG(L_e%Pefc@8>SeUXC8Yuz$kU|!W@9SGf@kuFS#)4=+f$f0 zFys@4tx}4l5~#iAOpt!w81*#*}G2>pi)A^LE4yJ zI}ywUkeH$GlDw>M(XBqwQ}GS0IJH2kJRR#t8NLgVTAzF;J=nV70LYQMk&E|$VdkP}GVyc71rk*;N`lrlF*eQyIw*|G%%RH1ZII2B^`Un<#bRN_ZX2b z19er^G;>1H8%A&^TM0wi?t{p{c*Ev^3*6@%;g~3ZhjM7(0`;Eai9Wof{Y|gNy+53w zn3m3}!3etgi1hiNdTd<`y%A~l{*`PtbLZ$1M!p&K6E~bce#^3O+qG!k60TD(xZhiP z<^>8>>lHajd%$8JMq9Xi#a+z4L>l|D<_`~WgB5*Azk!4-gl^8cL!;h-<>q1Tp;IUw zYb{|wE{8T1^sDfNO`(!7;EeX&B>-O2_1J_%aH65IS6M1VACjtZiU)}j&y4-WGp`Fh zxfTr@$#E`5M1#cb6x{_vs5K{dk*Z(b1n`-JyY|Ii;CB&nS?acJuj;?8?Uuk%t~>4( zTpb5=>73*02=radA6C~j=CzH!2mXXmg@FMIWBlBp_=-CuY7WAWp3J#2dO@ElcYea_k(WJlY@ANM@`RarMevOo z4MUe|Fokd(-D8=3c8~=R9P?~-Ve{4Ph~#20*R0ToR##Ef&Nsb11FfPbjR0I;U&e*2 z^T>!Uoj%*MF%7Wfgc0{DSTZT!2&=LN5h;PF)&=qgHJX+Zjo`q9Bdo(5{qkXNYbhAl zygx#r@p-)tPHoJxpT0DyvGRblgHBNOhb&P+VrFV?a&C6H>ddSi9}_0W?{ivQXi@)9 zl9-y9BeSqu`%h5Ap%u!MSRj0b=2&On@+!^()>K_>73ap5Dh{vQ&@*v-)g+|?Zk;z7 zMnZ8YCcn#Av>DzMuxbz;n8~RYbGmkHAA7cMV*~cxOY3=mk>JuSRMykm%M$X4P zTYHYf&F2U#O%F4DYI50<7mAd9{Y!mhOa2_Jt54WeHk1+;41gt8US1Ux#o0b@Rg{(B zfHr98x}qSIhkP?%3dvM-Q&7$KSfhl=C%@2J3y`X7(58?0-H$ki=DDBw12<)e64yzP zTjNB#E|DUDt3-gN&F|eW*Obo>YW$Opiwi4^B$*C*0>lWYDCmiZ&0ENcDAk3S%1BLc zNPj|G%rKVG@&RO&UUxTQqwpkkBxoU++ziZ*5w%ngxAJ!dJ2KFmmOZk}4Xz7Mbeq4O zas!1r>|wi&8B?~1^KE>i2KG@1Y&2SVG_<-Bhdg$z67540b&ZVS95xKo4~^=L{G9v& zA526^XQnar3)|vOkS}lTkat`cW(p z%5+3rOr#(Wp~<}G?T-x}W8N-<&*UiytQqXt9vAg+i;q8^y|e0F#s zAJTkPPlDs`%BVOWQTZ0402k*2+ctj<=ACayj`}hf$E{$bx^2lp+#8WcI?6S%<_!*U zZ8=qK08+SukwW-_v45(W0tp#&@*%HLG>6syAYRZkdg|eevBm14i`9(ndOQS%%ur=j zu55K$5~^b0==qsL-Mh-Z)k6W1`sl@nud-MOYR ztPJWaxF$AzB*djSR5-a61gD?Zzs5niJeQLT285C%O1Tc@(G~D;^wEX0qr4%xBLih` zB4`I+kHIAY>Cf^+$)c>ndRlJ1FW*9eg53$ zYmubnN54CU$eW~! z5d=)5i4X-}hmwHet4Ag*d2c9i*`x3FGBFVOa%vg+@^K)(@H%I#8m^m(56SQK=YgtT zq7w<>EyhMYz1q8Q{CsvAjIk*zypD({OJCX_H9OnF;7`A{5y7f^=GQun;jgCNCmD|6 zdx$-Bghi$3-9L)r{6JUR+1~2~1YUXo8^CsIFDW~4Lt*D*9D6(X%b2J;XbBxdZ-O|n z8T~Hn>NAm6Y91=~${R3>$m*!hCHIGLC;HVf?8cN6y3VnZJsz;?wz)WtF(h|h1+7?tjtN z2liMrrMqQSXB#oEE|x+Z6TaiKt%bA{p-nUP@JXz~4pZqNfs!j)Zvh zPwHHviA)XXL!3IshXzF?a014vdi|!piI{#mRNrDWP4X;m3ZfT2UVBYIMClP?M0~z4 z?~(K<6U5k)Xgc=lk_)^sIB*9*N+Ek6+JmDoKKSzCkf6N?y`|VN6N(yo?-WJBg5!!8 z`vj0UKkt8gN*KuLam()k6+2_}4!Jdi2<#H}XLH!V4X_{u>w5_FS|Rrw?&EhTBXb+! zXH1s48Fy%L#%p>W8X;F~H$#ku2Mj-q-X5PqjHacD3D5Ru5fVE;_~HOKzt@MYkwB5h zoH`sGMj*4ZV>oV{W?c^5$Jf1&rXb9vsJ}->)SosGrmoleXX{y^@%BED~D?aY6sLZlIG0 z#@XGSq>>n{IJXZ#eo2wR=-P=!ZB@%($^Z+94{#V=M=P)-FUmIVaTdeK%0q*h|_DjW*F4w~Q7E2Bz$;e5IU{RVt=0 zrY|Wewk+slbYDHQ_2?bxq_-WmVJ#7M*>p|@ES?a&S(56KPL4CxG&#EcNCF`KA&75f^yD_?xukseYQVi`Kr z;}jHaRdNb&vT*WnT3X)Gdw+7XEZ#6Pauy#5u-v3AFInIWgJT1^Zo-xc8kj75V#KNa zX>Tk}W*T}%LWBwBclviy-4EUO+d=LFyNrVi!wW+TBP#JZ;9s$hpK{2S@Y{sXrrQ_X zDRu=%oa6l&&gR-jcJt%>MP1a^4Be>*pK1{mOBu$wt=r#yPGu=c^RTXdSEa>5kg6~a z5L$nJSHrH2t)9+;!V<+C#Ujr8W&YN`X)&DRNn zBE26wvN+={oG9hw`&xa_*fO!fY5Ubk$NGz3)wouewzM|A*3Zw1X-Yq}r?grs_bd0S z(yPwit(SaNyAF1UcgXv!-J;Q=-(uJz4_xCctbTs46{Rh&P5oKoU10US%yrd~{DSKR zbN-sP) z7yLzrY9%|B<;;2!bH{#qv{ix|hOYE;h5m$(mokACGlM)Irw7SCHsRYcO{;XVBr$Tn z?Gm|2A4I{|WvEp)%4-*N58R0yRQYI#Ppt|`^p#M^Pc6_&lSvVL)t%=BIeaReN%^LD z&v>|6ilIP~5~O-BaG0=nU?tn=1{kEKJE?*bA*?^rx|lz>U(W9trnstoqrWTLLm2zb zK&>i~9l(AE-SZqHN#@&CHwifQ|VcG`%nX;cEn-ZDA$&Sr7<L+>vo8-y*$@9s{$>hoVN$V^zJ{;@k)U;IV3G$SMB;G_v!uKn=gG5-)0zB&ZU%qno8gmRjiyu2%nx2Sb?fRv zRjTE&bFU5>y+rf$bt@@8QxtufjbGG0WISLzB==SkEpUmfl@-!`pYrKQ=h)|PV?MC@ zL7Qvo{lb@PvU_D9P$=-zM(NBF$$|e-?Df+%!nM$m{P7nU0W1Y3;8zh85!Cdo@kDT6 zaXoWnI{O>iQ}w#?bv2;-lK(9IB!Ay@Uw8crw)ty%!Z_XE@a%G}6SFGv3^|W>DbZHg zPS{-7UfBBf`vK3iz=lf~)HmTGXcv8#b=Sc1i+joi%Pt=>5R21+Qy5_wWAj(oyK~M=(mR6xx zCSt6p+TdUKZg!d3Rc-@ihf+czP(~;Sx?~ga!vbt;VrJsHVYcD2VIMTzHS^ebCvXM2 zGTeVZ88rnIWWMGDT$A)l)0tz}@NG5p@i|!1`IRDHLFcFDm)=>iG{D+0n=u5saNw zx0l3;)wgMj%`lE*DBT6R+~~CKESl4oZp+r3wk)@Nq`h zrvodCKLnQrf3z-xTb=Wm)%^;fT2yITobmBcmuZ;t<3>G`Yv;G?@d@s)f> zuKLx}z>}vF>zkw-#Rt*{;Rl%q2LFGxE*hzyBBJh+_*+-j-+q zzXAH#@k3r~?TVhykI&mysbhyAzP?jOVW!4_WqFBAC}h5V=d zW&i&vg&g305dNZ#ZS@ZDFG&B@dXpP`$Umu&JG|w;n>=@T+jLcU#0)blcx2lD3t0Rg z;t?0_RLU3+K1BmW`H#x{KOn{gM|iS-x&H^m_&>RDaHS!$|F7J?U?T@167qk<4}bSD Nb2zv*5%|B>{{rxqa{&MV delta 449 zcmbQXoomJuPTl}-W)?065D;c(p2%y)45S*}wz@H{*JBA^TI;v{ryip?BbYh;VGE=7 z^bPA6m9{4uFmASC$?R$M+b)sIc!LR~Yx?JWMjPe=Amc#`qtW#J1&lJ&8wwb?KtkJl z3m5}LV3HAFA?sGg31CUE`e_pw)xg4<6Bz$+u>j2robJ%eXb2RSnO@Msm^;07GLy*m z@3R?K6+$dt%FCq7$Okk$5bS&~G1-w-ak@hv6WjDyekO5*_1gSQCQQ7HOmfU{zfM19 z$>aud_jZ0OrlpV3OLdI+^JSE5t6|nM{pfGbheu cN(M8&&tys$VPyk(? Date: Fri, 4 Sep 2020 13:40:55 -0700 Subject: [PATCH 36/66] cleanups of compile errors and subtle\n changes to the call structure so progammers see what the \n template pattern implemenation looks like at runtime --- Design-Patterns.playground.zip | Bin 170902 -> 171057 bytes .../Contents.swift | 12 ++++++------ README.md | 12 ++++++------ source/behavioral/template_method.swift | 12 ++++++------ 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Design-Patterns.playground.zip b/Design-Patterns.playground.zip index bbc75e2c6c2bab5b26bf521fec27e524290f1f54..70b8291d3cf8ad8e37396c299a26fe1b6d3dc851 100644 GIT binary patch delta 16180 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 E9|gV3KL7v# delta 15947 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 Date: Wed, 11 Nov 2020 15:36:11 -0300 Subject: [PATCH 37/66] Add monostate example --- Design-Patterns.playground.zip | Bin 171057 -> 185397 bytes .../Contents.swift | 37 ++++++++++++++++ README.md | 41 ++++++++++++++++++ source/creational/monostate.swift | 37 ++++++++++++++++ 4 files changed, 115 insertions(+) create mode 100644 source/creational/monostate.swift diff --git a/Design-Patterns.playground.zip b/Design-Patterns.playground.zip index 70b8291d3cf8ad8e37396c299a26fe1b6d3dc851..8dec9421ed0ae67707556e7c67812dd2a2f42020 100644 GIT binary patch delta 16861 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 diff --git a/Design-Patterns.playground/Pages/Creational.xcplaygroundpage/Contents.swift b/Design-Patterns.playground/Pages/Creational.xcplaygroundpage/Contents.swift index 6b46311..91b9015 100644 --- a/Design-Patterns.playground/Pages/Creational.xcplaygroundpage/Contents.swift +++ b/Design-Patterns.playground/Pages/Creational.xcplaygroundpage/Contents.swift @@ -192,6 +192,43 @@ CurrencyFactory.currency(for: .greece)?.code ?? noCurrencyCode CurrencyFactory.currency(for: .spain)?.code ?? noCurrencyCode CurrencyFactory.currency(for: .unitedStates)?.code ?? noCurrencyCode CurrencyFactory.currency(for: .uk)?.code ?? noCurrencyCode +/*: + 🔂 Monostate + ------------ + + The monostate pattern is a alternativa to singleton, so in that case monostate still + the state as static instead of all object as singleton. You can use a protocol to apply + dependency inversion helping you on unit tests. + +### Example: +*/ +struct Settings { + + enum Theme { + case .old + case .new + } + + private static var theme: Theme + + var currentTheme: Theme { + get { Settings.theme } + set(newTheme) { Settings.theme = newTheme } + } +} +/*: +### Usage: +*/ + +// When change the theme +let settings = Settings() // Starts using theme .old +settings.theme = .new // Change theme to .new + +//On Screen 1 +let screenColor: Color = Settings().theme == .old ? .gray : .white + +//On Screen 2 +let screenTitle: String = Settings().theme == .old ? "Itunes Connect" : "App Store Connect" /*: 🃏 Prototype ------------ diff --git a/README.md b/README.md index 35dc5d1..3818836 100644 --- a/README.md +++ b/README.md @@ -1002,6 +1002,47 @@ CurrencyFactory.currency(for: .greece)?.code ?? noCurrencyCode CurrencyFactory.currency(for: .spain)?.code ?? noCurrencyCode CurrencyFactory.currency(for: .unitedStates)?.code ?? noCurrencyCode CurrencyFactory.currency(for: .uk)?.code ?? noCurrencyCode +``` + + 🔂 Monostate + ------------ + + The monostate pattern is a alternativa to singleton, so in that case monostate still + the state as static instead of all object as singleton. You can use a protocol to apply + dependency inversion helping you on unit tests. + +### Example: + +```swift +struct Settings { + + enum Theme { + case .old + case .new + } + + private static var theme: Theme + + var currentTheme: Theme { + get { Settings.theme } + set(newTheme) { Settings.theme = newTheme } + } +} +``` + +### Usage: + +```swift + +// When change the theme +let settings = Settings() // Starts using theme .old +settings.theme = .new // Change theme to .new + +//On Screen 1 +let screenColor: Color = Settings().theme == .old ? .gray : .white + +//On Screen 2 +let screenTitle: String = Settings().theme == .old ? "Itunes Connect" : "App Store Connect" ``` 🃏 Prototype diff --git a/source/creational/monostate.swift b/source/creational/monostate.swift new file mode 100644 index 0000000..61392aa --- /dev/null +++ b/source/creational/monostate.swift @@ -0,0 +1,37 @@ +/*: + 🔂 Monostate + ------------ + + The monostate pattern is a alternativa to singleton, so in that case monostate still + the state as static instead of all object as singleton. You can use a protocol to apply + dependency inversion helping you on unit tests. + +### Example: +*/ +struct Settings { + + enum Theme { + case .old + case .new + } + + private static var theme: Theme + + var currentTheme: Theme { + get { Settings.theme } + set(newTheme) { Settings.theme = newTheme } + } +} +/*: +### Usage: +*/ + +// When change the theme +let settings = Settings() // Starts using theme .old +settings.theme = .new // Change theme to .new + +//On Screen 1 +let screenColor: Color = Settings().theme == .old ? .gray : .white + +//On Screen 2 +let screenTitle: String = Settings().theme == .old ? "Itunes Connect" : "App Store Connect" From 1bf272dd031451282ab8cb17ca512e55f5777765 Mon Sep 17 00:00:00 2001 From: Victor C Tavernari Date: Wed, 11 Nov 2020 15:44:20 -0300 Subject: [PATCH 38/66] Fix texts and index --- Design-Patterns.playground.zip | Bin 185397 -> 185396 bytes .../Contents.swift | 8 +++----- README.md | 10 ++++------ source/contentsReadme.md | 2 +- source/creational/monostate.swift | 8 +++----- 5 files changed, 11 insertions(+), 17 deletions(-) diff --git a/Design-Patterns.playground.zip b/Design-Patterns.playground.zip index 8dec9421ed0ae67707556e7c67812dd2a2f42020..ef10871f6271b5d0e7dce55f00e563b5698b7f0e 100644 GIT binary patch delta 3102 zcmZ8jcRZEtA9kLDW1M8q?Cls?>5w8SBRiFKUX@M9j!=h?@yg~gB1g!`I%a0sI?C*1 z%L>_Kl=U9<{;K!){BwV<>wA5#`+MKd{l`_2OI@Bz?OzU&ashlEfYL4y6XIGG;R11F z{Fjgg-$z1Df&MNKDjJ^$jt1{VDhJ0XNJvhzfiW=<;h)u`CB zuOUmu&00WlJQd3RadtMRW2Gr>^X3W_q*}*_XXcCKS$oS439$-vJbcIl!Qqc)s6R8f zp_Mi687;TG=c|wI$luF1n``j)IIR~O%si@PyeWfRc&ND%Tc4L~fbeavu*^i^O(`T6 zw|Mc2G>O#wALTKQ)fE>%KBikn^?HZ8_-B$p=iF&P!aR9>yHeqVn2uDzy% z+;xP;OSnq_N$X-Z*FX)zzhMcgqfcA+yliv#s*9_e>okxNdd#xVyx6u>99 zO=FsvKo8p}nd+j@ZXd`bb#trfG?xR~`~^OVSnJ}gS`j8_A!U`TB<8w1mq5-fUzO${ zs@-n3=$9kk^AZv?I&1X?7kzbAG-I7BaAHQ;ytWtt9q&7Hg(&I+t)#1X!Lj|2ph+*h z{HH2HwOUQwt4#^!q9Isio9cNX?zon-EM=E?gXmB_e$QST4z`oUW^g)6?&@?`J1oMn zp8Pqo+h1oj&Xsa=mKKjVgbl`d5U8j|PjIY$pD)lFyg2*%qn4qIm7v1oH2hZa{a%9K z$YD1|npeM9kD8}we51o-Z-Aju0cpk1sHfLRN2p9Tt21P(a&S|2mq|+v`Ft2|tKjV5 zKVv?2gmF4SKDCgV;#X%a7CbPd8*#QStfughG;c@InJ27iuQlIRtENQk^hwooKUMzL z)y&Sri=Yjhbtw7Ll9QHyze;+on?@z4YydHep_7qYF+et_a!`L8{1$Dl5wJ&CtKgY1 znDG$8#g($`LDlnGWaQ=zig;D6zKX7QACbNicgMz!kyd|QjGC?2r&qi6g&w3U7l&LEY?ka6MXD^#*D|t$uJhjP5Sq4c8@h}3u^GK@Yti+ch&0g>1 zZ)mb+?_9S--yB_)gLnCw6UQAmBk!+RcoFc6H`Z3pO;Ya=RdBlK1SnUY(R%rQ_P^yY#gG7J)iVqte%N-Q(kz$7Vq~uQ%d?Mr>i4JX1})~s<*paZKP5wRu-R->eA#au z9UhVZ1)l^lL>!J(#n3#s5Vew=mP5*U&!>j}@ItAQ6h?Zdr~NO<8Ji0TWc0y)|6dqO zmi+6as*GdH178}1ueo|9SzwT!N<|X54Z?%43?Zr;8U6?>t&euRb95*g7$3Zmslk0? z)y@Ri6~$1cx4#U(97z@1ouAAfHgRbw|f`rA-L`y8ffL8 zM;SRz7NnQOPIajlKlPZB<_!oAe6R976zc?%H+ik zN&AFtb)YD+thNt5HT#oSKA#WOe-RzQktnpHOu)fSDJ@e^G5JKylH1q2KBKsA(xxBq z@^OmeBs+^P^l!PM7wb;zfr758dYo#|UXy&&YUhh9ft;Qf{UtEU)6CWcK70OnOG3WH z5GVGQ+-7teHY~QmIGm|XgngsEP?w^BI{V9NLc_ufZm{A0hp|g6aI(uBW?e%ZtbR@D z7ktmKT0Dj~8?;t@D%W&rZ@k6$T})eeN9`a{R7pN}f;xYGb*W!Iw{bX5`e-Kh#*%sb zEGYwP8aixlE@KH(-Dhb!blew}3h12pPvQc7TY+#OG7@~#4DcTZFDcNZ4G;saM*UZtO+JURbP?C58i1#s6`NJc-gXrP) z6r5}aF8po>`8$cUd>Y7G0dRtrod62R{0-zl+H?pPDD{>&Y=7}D4Id~~0%1yg4^V-x z-V)nYOa5D8082`Kw!uMTJW-(D^oJm$3BvND_rr0i{Ld0?Geq`yH#q3tMXXIt|7)k)CcOlF~YZ0LA|5(Q34gnDR9uRP@at>gm{$cmS4G#A90@=_G zCm_y%_y|n<0ctRVcsMBh?k`5<*q$6@=_d|<_cv`09sCVsK-d5vLVnE|Alm)|R;i{k delta 3061 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 HfGYbxYtEUT diff --git a/Design-Patterns.playground/Pages/Creational.xcplaygroundpage/Contents.swift b/Design-Patterns.playground/Pages/Creational.xcplaygroundpage/Contents.swift index 91b9015..f682de8 100644 --- a/Design-Patterns.playground/Pages/Creational.xcplaygroundpage/Contents.swift +++ b/Design-Patterns.playground/Pages/Creational.xcplaygroundpage/Contents.swift @@ -196,9 +196,7 @@ CurrencyFactory.currency(for: .uk)?.code ?? noCurrencyCode 🔂 Monostate ------------ - The monostate pattern is a alternativa to singleton, so in that case monostate still - the state as static instead of all object as singleton. You can use a protocol to apply - dependency inversion helping you on unit tests. + The monostate pattern is an alternative to singleton, so in that case, monostate saves the state as static instead of the entire instance as a singleton. You can use a protocol to apply dependency inversion helping you on unit tests. ### Example: */ @@ -224,10 +222,10 @@ struct Settings { let settings = Settings() // Starts using theme .old settings.theme = .new // Change theme to .new -//On Screen 1 +//On screen 1 let screenColor: Color = Settings().theme == .old ? .gray : .white -//On Screen 2 +//On screen 2 let screenTitle: String = Settings().theme == .old ? "Itunes Connect" : "App Store Connect" /*: 🃏 Prototype diff --git a/README.md b/README.md index 3818836..017a8dd 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ print("Welcome!") | [👫 Command](#-command) | [👷 Builder](#-builder) | [🌉 Bridge](#-bridge) | | [🎶 Interpreter](#-interpreter) | [🏭 Factory Method](#-factory-method) | [🌿 Composite](#-composite) | | [🍫 Iterator](#-iterator) | [🃏 Prototype](#-prototype) | [🍧 Decorator](#-decorator) | -| [💐 Mediator](#-mediator) | [💍 Singleton](#-singleton) | [🎁 Façade](#-fa-ade) | +| [💐 Mediator](#-mediator) | [💍 Singleton](#-singleton) || [🔂 Monostate](#-monostate) | [🎁 Façade](#-fa-ade) | | [💾 Memento](#-memento) | | [🍃 Flyweight](#-flyweight) | | [👓 Observer](#-observer) | | [☔ Protection Proxy](#-protection-proxy) | | [🐉 State](#-state) | | [🍬 Virtual Proxy](#-virtual-proxy) | @@ -1007,9 +1007,7 @@ CurrencyFactory.currency(for: .uk)?.code ?? noCurrencyCode 🔂 Monostate ------------ - The monostate pattern is a alternativa to singleton, so in that case monostate still - the state as static instead of all object as singleton. You can use a protocol to apply - dependency inversion helping you on unit tests. + The monostate pattern is an alternative to singleton, so in that case, monostate saves the state as static instead of the entire instance as a singleton. You can use a protocol to apply dependency inversion helping you on unit tests. ### Example: @@ -1038,10 +1036,10 @@ struct Settings { let settings = Settings() // Starts using theme .old settings.theme = .new // Change theme to .new -//On Screen 1 +//On screen 1 let screenColor: Color = Settings().theme == .old ? .gray : .white -//On Screen 2 +//On screen 2 let screenTitle: String = Settings().theme == .old ? "Itunes Connect" : "App Store Connect" ``` diff --git a/source/contentsReadme.md b/source/contentsReadme.md index 7a92ac8..2024e21 100644 --- a/source/contentsReadme.md +++ b/source/contentsReadme.md @@ -7,7 +7,7 @@ | [👫 Command](#-command) | [👷 Builder](#-builder) | [🌉 Bridge](#-bridge) | | [🎶 Interpreter](#-interpreter) | [🏭 Factory Method](#-factory-method) | [🌿 Composite](#-composite) | | [🍫 Iterator](#-iterator) | [🃏 Prototype](#-prototype) | [🍧 Decorator](#-decorator) | -| [💐 Mediator](#-mediator) | [💍 Singleton](#-singleton) | [🎁 Façade](#-fa-ade) | +| [💐 Mediator](#-mediator) | [💍 Singleton](#-singleton) || [🔂 Monostate](#-monostate) | [🎁 Façade](#-fa-ade) | | [💾 Memento](#-memento) | | [🍃 Flyweight](#-flyweight) | | [👓 Observer](#-observer) | | [☔ Protection Proxy](#-protection-proxy) | | [🐉 State](#-state) | | [🍬 Virtual Proxy](#-virtual-proxy) | diff --git a/source/creational/monostate.swift b/source/creational/monostate.swift index 61392aa..bb24e53 100644 --- a/source/creational/monostate.swift +++ b/source/creational/monostate.swift @@ -2,9 +2,7 @@ 🔂 Monostate ------------ - The monostate pattern is a alternativa to singleton, so in that case monostate still - the state as static instead of all object as singleton. You can use a protocol to apply - dependency inversion helping you on unit tests. + The monostate pattern is an alternative to singleton, so in that case, monostate saves the state as static instead of the entire instance as a singleton. You can use a protocol to apply dependency inversion helping you on unit tests. ### Example: */ @@ -30,8 +28,8 @@ struct Settings { let settings = Settings() // Starts using theme .old settings.theme = .new // Change theme to .new -//On Screen 1 +//On screen 1 let screenColor: Color = Settings().theme == .old ? .gray : .white -//On Screen 2 +//On screen 2 let screenTitle: String = Settings().theme == .old ? "Itunes Connect" : "App Store Connect" From e2fa0a48ee0133d1cda24ac819517ad9a4f0da85 Mon Sep 17 00:00:00 2001 From: Victor C Tavernari Date: Wed, 11 Nov 2020 15:45:20 -0300 Subject: [PATCH 39/66] Fix index --- Design-Patterns.playground.zip | Bin 185396 -> 185396 bytes README.md | 8 ++++---- source/contentsReadme.md | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Design-Patterns.playground.zip b/Design-Patterns.playground.zip index ef10871f6271b5d0e7dce55f00e563b5698b7f0e..ab0f268afd22de0ad6c9e338025bba2396e2204d 100644 GIT binary patch delta 181 zcmdn8f_uvf?uIRl`UOlCYo;3(Fh&CD?L7sI*&r d(R;@sqPi!T{;`2XbgeE_Iz-(eGriCm3VSqy! diff --git a/README.md b/README.md index 017a8dd..99bb1d2 100644 --- a/README.md +++ b/README.md @@ -27,10 +27,10 @@ print("Welcome!") | [👫 Command](#-command) | [👷 Builder](#-builder) | [🌉 Bridge](#-bridge) | | [🎶 Interpreter](#-interpreter) | [🏭 Factory Method](#-factory-method) | [🌿 Composite](#-composite) | | [🍫 Iterator](#-iterator) | [🃏 Prototype](#-prototype) | [🍧 Decorator](#-decorator) | -| [💐 Mediator](#-mediator) | [💍 Singleton](#-singleton) || [🔂 Monostate](#-monostate) | [🎁 Façade](#-fa-ade) | -| [💾 Memento](#-memento) | | [🍃 Flyweight](#-flyweight) | -| [👓 Observer](#-observer) | | [☔ Protection Proxy](#-protection-proxy) | -| [🐉 State](#-state) | | [🍬 Virtual Proxy](#-virtual-proxy) | +| [💐 Mediator](#-mediator) | [💍 Singleton](#-singleton) | [🎁 Façade](#-fa-ade) | +| [💾 Memento](#-memento) | [🔂 Monostate](#-monostate) | [🍃 Flyweight](#-flyweight) | +| [👓 Observer](#-observer) | | [☔ Protection Proxy](#-protection-proxy) | +| [🐉 State](#-state) | | [🍬 Virtual Proxy](#-virtual-proxy) | | [💡 Strategy](#-strategy) | | | | [🏃 Visitor](#-visitor) | | | diff --git a/source/contentsReadme.md b/source/contentsReadme.md index 2024e21..d6c5d9e 100644 --- a/source/contentsReadme.md +++ b/source/contentsReadme.md @@ -7,10 +7,10 @@ | [👫 Command](#-command) | [👷 Builder](#-builder) | [🌉 Bridge](#-bridge) | | [🎶 Interpreter](#-interpreter) | [🏭 Factory Method](#-factory-method) | [🌿 Composite](#-composite) | | [🍫 Iterator](#-iterator) | [🃏 Prototype](#-prototype) | [🍧 Decorator](#-decorator) | -| [💐 Mediator](#-mediator) | [💍 Singleton](#-singleton) || [🔂 Monostate](#-monostate) | [🎁 Façade](#-fa-ade) | -| [💾 Memento](#-memento) | | [🍃 Flyweight](#-flyweight) | -| [👓 Observer](#-observer) | | [☔ Protection Proxy](#-protection-proxy) | -| [🐉 State](#-state) | | [🍬 Virtual Proxy](#-virtual-proxy) | +| [💐 Mediator](#-mediator) | [💍 Singleton](#-singleton) | [🎁 Façade](#-fa-ade) | +| [💾 Memento](#-memento) | [🔂 Monostate](#-monostate) | [🍃 Flyweight](#-flyweight) | +| [👓 Observer](#-observer) | | [☔ Protection Proxy](#-protection-proxy) | +| [🐉 State](#-state) | | [🍬 Virtual Proxy](#-virtual-proxy) | | [💡 Strategy](#-strategy) | | | | [🏃 Visitor](#-visitor) | | | From d6c38c9477888891cd84877ba457f8732cd8e775 Mon Sep 17 00:00:00 2001 From: Victor C Tavernari Date: Wed, 11 Nov 2020 21:55:59 -0300 Subject: [PATCH 40/66] Add better description --- Design-Patterns.playground.zip | Bin 185396 -> 185517 bytes .../Contents.swift | 4 +++- README.md | 4 +++- source/creational/monostate.swift | 4 +++- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Design-Patterns.playground.zip b/Design-Patterns.playground.zip index ab0f268afd22de0ad6c9e338025bba2396e2204d..6c0985e0ca2d038ab1866a8b98b2b12225b95bea 100644 GIT binary patch delta 3211 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 delta 3135 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 Date: Wed, 11 Nov 2020 22:05:10 -0300 Subject: [PATCH 41/66] Fix invalid property --- Design-Patterns.playground.zip | Bin 185517 -> 185522 bytes .../Contents.swift | 6 +++--- README.md | 6 +++--- source/creational/monostate.swift | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Design-Patterns.playground.zip b/Design-Patterns.playground.zip index 6c0985e0ca2d038ab1866a8b98b2b12225b95bea..8a316045d5f57a041c70b4f7f4beae0e7b977599 100644 GIT binary patch delta 3188 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 Date: Wed, 11 Nov 2020 22:12:31 -0300 Subject: [PATCH 42/66] Fix sort index --- Design-Patterns.playground.zip | Bin 185522 -> 185522 bytes README.md | 6 +++--- source/contentsReadme.md | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Design-Patterns.playground.zip b/Design-Patterns.playground.zip index 8a316045d5f57a041c70b4f7f4beae0e7b977599..e7716fb44be20815f3491f86b58c57680e9a68a3 100644 GIT binary patch delta 193 zcmdnAl6%ui?uIRl`UOla8>br$~6aq4VMUY8qGe|(; z2va7A?moiw70Q>HKJO@#FG$tfqfCKJAW?@CU{%{!pJ4jO1`=3(o+$;SLhu69LKXn< CxlBg@ diff --git a/README.md b/README.md index 0cb4065..7c30fa6 100644 --- a/README.md +++ b/README.md @@ -26,9 +26,9 @@ print("Welcome!") | [🐝 Chain Of Responsibility](#-chain-of-responsibility) | [🌰 Abstract Factory](#-abstract-factory) | [🔌 Adapter](#-adapter) | | [👫 Command](#-command) | [👷 Builder](#-builder) | [🌉 Bridge](#-bridge) | | [🎶 Interpreter](#-interpreter) | [🏭 Factory Method](#-factory-method) | [🌿 Composite](#-composite) | -| [🍫 Iterator](#-iterator) | [🃏 Prototype](#-prototype) | [🍧 Decorator](#-decorator) | -| [💐 Mediator](#-mediator) | [💍 Singleton](#-singleton) | [🎁 Façade](#-fa-ade) | -| [💾 Memento](#-memento) | [🔂 Monostate](#-monostate) | [🍃 Flyweight](#-flyweight) | +| [🍫 Iterator](#-iterator) | [🔂 Monostate](#-monostate) | [🍧 Decorator](#-decorator) | +| [💐 Mediator](#-mediator) | [🃏 Prototype](#-prototype) | [🎁 Façade](#-fa-ade) | +| [💾 Memento](#-memento) | [💍 Singleton](#-singleton) | [🍃 Flyweight](#-flyweight) | | [👓 Observer](#-observer) | | [☔ Protection Proxy](#-protection-proxy) | | [🐉 State](#-state) | | [🍬 Virtual Proxy](#-virtual-proxy) | | [💡 Strategy](#-strategy) | | | diff --git a/source/contentsReadme.md b/source/contentsReadme.md index d6c5d9e..fa748a3 100644 --- a/source/contentsReadme.md +++ b/source/contentsReadme.md @@ -6,9 +6,9 @@ | [🐝 Chain Of Responsibility](#-chain-of-responsibility) | [🌰 Abstract Factory](#-abstract-factory) | [🔌 Adapter](#-adapter) | | [👫 Command](#-command) | [👷 Builder](#-builder) | [🌉 Bridge](#-bridge) | | [🎶 Interpreter](#-interpreter) | [🏭 Factory Method](#-factory-method) | [🌿 Composite](#-composite) | -| [🍫 Iterator](#-iterator) | [🃏 Prototype](#-prototype) | [🍧 Decorator](#-decorator) | -| [💐 Mediator](#-mediator) | [💍 Singleton](#-singleton) | [🎁 Façade](#-fa-ade) | -| [💾 Memento](#-memento) | [🔂 Monostate](#-monostate) | [🍃 Flyweight](#-flyweight) | +| [🍫 Iterator](#-iterator) | [🔂 Monostate](#-monostate) | [🍧 Decorator](#-decorator) | +| [💐 Mediator](#-mediator) | [🃏 Prototype](#-prototype) | [🎁 Façade](#-fa-ade) | +| [💾 Memento](#-memento) | [💍 Singleton](#-singleton) | [🍃 Flyweight](#-flyweight) | | [👓 Observer](#-observer) | | [☔ Protection Proxy](#-protection-proxy) | | [🐉 State](#-state) | | [🍬 Virtual Proxy](#-virtual-proxy) | | [💡 Strategy](#-strategy) | | | From 5d5b73695913706561d5e84b969d600e702259c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=85=B4=E5=BD=AC=5FBinboy?= Date: Sun, 29 Mar 2020 19:34:41 +0800 Subject: [PATCH 43/66] Create deploy-chinese.yml --- .github/workflows/deploy-chinese.yml | 42 ++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 .github/workflows/deploy-chinese.yml diff --git a/.github/workflows/deploy-chinese.yml b/.github/workflows/deploy-chinese.yml new file mode 100644 index 0000000..7c00059 --- /dev/null +++ b/.github/workflows/deploy-chinese.yml @@ -0,0 +1,42 @@ +name: Deploy Chinese + +# Controls when the action will run. Triggers the workflow on push or pull request +# events but only for the master branch +on: + push: + branches: [master] + pull_request: + branches: [master] + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + build: + # The type of runner that the job will run on + runs-on: macos-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v2 + + # Checkout to chinese branch & Generate Chinese + - name: Generate Chinese Readme + run: | + ./generate-playground-cn.sh + mv ./README-CN.md ./README.md + + # Commit + - name: Commit files + run: | + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + git add README.md + git commit -m "Generate Chinese version" + ## Push changes to chinese branch + - name: Push changes + uses: ad-m/github-push-action@master + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + branch: "chinese" + force: true From 960098e2e02da6401872f8c76efdf219cec304f3 Mon Sep 17 00:00:00 2001 From: Binlogo Date: Fri, 30 Apr 2021 13:46:25 +0800 Subject: [PATCH 44/66] Fix monostate pattern build issue and fit reference type --- Design-Patterns.playground.zip | Bin 185522 -> 199169 bytes .../Contents.swift | 17 ++++++++++------- .../timeline.xctimeline | 6 ++++++ README.md | 17 ++++++++++------- source/creational/monostate.swift | 17 ++++++++++------- 5 files changed, 36 insertions(+), 21 deletions(-) create mode 100644 Design-Patterns.playground/Pages/Creational.xcplaygroundpage/timeline.xctimeline diff --git a/Design-Patterns.playground.zip b/Design-Patterns.playground.zip index e7716fb44be20815f3491f86b58c57680e9a68a3..0498dfd41cb8d678a0a1321324f3ca6cff8e9a88 100644 GIT binary patch delta 16320 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 delta 3512 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 + + + + diff --git a/README.md b/README.md index 7c30fa6..6a0bc4d 100644 --- a/README.md +++ b/README.md @@ -1014,17 +1014,18 @@ CurrencyFactory.currency(for: .uk)?.code ?? noCurrencyCode ### Example: ```swift -struct Settings { +class Settings { enum Theme { - case .old - case .new + case `default` + case old + case new } - private static var theme: Theme + private static var theme: Theme? var currentTheme: Theme { - get { Settings.theme } + get { Settings.theme ?? .default } set(newTheme) { Settings.theme = newTheme } } } @@ -1034,14 +1035,16 @@ struct Settings { ```swift +import SwiftUI + // When change the theme let settings = Settings() // Starts using theme .old settings.currentTheme = .new // Change theme to .new -//On screen 1 +// On screen 1 let screenColor: Color = Settings().currentTheme == .old ? .gray : .white -//On screen 2 +// On screen 2 let screenTitle: String = Settings().currentTheme == .old ? "Itunes Connect" : "App Store Connect" ``` diff --git a/source/creational/monostate.swift b/source/creational/monostate.swift index afd92cb..90af5a4 100644 --- a/source/creational/monostate.swift +++ b/source/creational/monostate.swift @@ -8,17 +8,18 @@ ### Example: */ -struct Settings { +class Settings { enum Theme { - case .old - case .new + case `default` + case old + case new } - private static var theme: Theme + private static var theme: Theme? var currentTheme: Theme { - get { Settings.theme } + get { Settings.theme ?? .default } set(newTheme) { Settings.theme = newTheme } } } @@ -26,12 +27,14 @@ struct Settings { ### Usage: */ +import SwiftUI + // When change the theme let settings = Settings() // Starts using theme .old settings.currentTheme = .new // Change theme to .new -//On screen 1 +// On screen 1 let screenColor: Color = Settings().currentTheme == .old ? .gray : .white -//On screen 2 +// On screen 2 let screenTitle: String = Settings().currentTheme == .old ? "Itunes Connect" : "App Store Connect" From 7b0dccedb570e9b9d24fbd103710693332892642 Mon Sep 17 00:00:00 2001 From: Binlogo Date: Fri, 30 Apr 2021 21:01:07 +0800 Subject: [PATCH 45/66] Translate monostate pattern --- .../Contents.swift | 39 +++++++ README-CN.md | 102 +++++++++++++++++- source-cn/contentsReadme.md | 6 +- source-cn/creational/monostate.swift | 39 +++++++ 4 files changed, 180 insertions(+), 6 deletions(-) create mode 100644 source-cn/creational/monostate.swift diff --git a/Design-Patterns-CN.playground/Pages/Creational.xcplaygroundpage/Contents.swift b/Design-Patterns-CN.playground/Pages/Creational.xcplaygroundpage/Contents.swift index bb454a1..e7d20d9 100644 --- a/Design-Patterns-CN.playground/Pages/Creational.xcplaygroundpage/Contents.swift +++ b/Design-Patterns-CN.playground/Pages/Creational.xcplaygroundpage/Contents.swift @@ -189,6 +189,45 @@ CurrencyFactory.currency(for: .greece)?.code ?? noCurrencyCode CurrencyFactory.currency(for: .spain)?.code ?? noCurrencyCode CurrencyFactory.currency(for: .unitedStates)?.code ?? noCurrencyCode CurrencyFactory.currency(for: .uk)?.code ?? noCurrencyCode +/*: + 🔂 单态(Monostate) + ------------ + + 单态模式是实现单一共享的另一种方法。不同于单例模式,它通过完全不同的机制,在不限制构造方法的情况下实现单一共享特性。 + 因此,在这种情况下,单态会将状态保存为静态,而不是将整个实例保存为单例。 + [单例和单态 - Robert C. Martin](http://staff.cs.utu.fi/~jounsmed/doos_06/material/SingletonAndMonostate.pdf) + +### 示例: +*/ +class Settings { + + enum Theme { + case `default` + case old + case new + } + + private static var theme: Theme? + + var currentTheme: Theme { + get { Settings.theme ?? .default } + set(newTheme) { Settings.theme = newTheme } + } +} +/*: +### 用法: +*/ +import SwiftUI + +// 改变主题 +let settings = Settings() // 开始使用主题 .old +settings.currentTheme = .new // 改变主题为 .new + +// 界面一 +let screenColor: Color = Settings().currentTheme == .old ? .gray : .white + +// 界面二 +let screenTitle: String = Settings().currentTheme == .old ? "Itunes Connect" : "App Store Connect" /*: 🃏 原型(Prototype) -------------- diff --git a/README-CN.md b/README-CN.md index ec2c8a3..2d6af61 100644 --- a/README-CN.md +++ b/README-CN.md @@ -22,9 +22,9 @@ print("您好!") | [🐝 责任链 Chain Of Responsibility](#-责任链chain-of-responsibility) | [🌰 抽象工厂 Abstract Factory](#-抽象工厂abstract-factory) | [🔌 适配器 Adapter](#-适配器adapter) | | [👫 命令 Command](#-命令command) | [👷 生成器 Builder](#-生成器builder) | [🌉 桥接 Bridge](#-桥接bridge) | | [🎶 解释器 Interpreter](#-解释器interpreter) | [🏭 工厂方法 Factory Method](#-工厂方法factory-method) | [🌿 组合 Composite](#-组合composite) | -| [🍫 迭代器 Iterator](#-迭代器iterator) | [🃏 原型 Prototype](#-原型prototype) | [🍧 修饰 Decorator](#-修饰decorator) | -| [💐 中介者 Mediator](#-中介者mediator) | [💍 单例 Singleton](#-单例singleton) | [🎁 外观 Façade](#-外观facade) | -| [💾 备忘录 Memento](#-备忘录memento) | | [🍃 享元 Flyweight](#-享元flyweight) | +| [🍫 迭代器 Iterator](#-迭代器iterator) | [🔂 单态 Monostate](#-单态monostate) | [🍧 修饰 Decorator](#-修饰decorator) | +| [💐 中介者 Mediator](#-中介者mediator) | [🃏 原型 Prototype](#-原型prototype) | [🎁 外观 Façade](#-外观facade) | +| [💾 备忘录 Memento](#-备忘录memento) | [💍 单例 Singleton](#-单例singleton) | [🍃 享元 Flyweight](#-享元flyweight) | | [👓 观察者 Observer](#-观察者observer) | | [☔ 保护代理 Protection Proxy](#-保护代理模式protection-proxy) | | [🐉 状态 State](#-状态state) | | [🍬 虚拟代理 Virtual Proxy](#-虚拟代理virtual-proxy) | | [💡 策略 Strategy](#-策略strategy) | | | @@ -687,6 +687,59 @@ let gaff = BladeRunner(test: GeneticTest()) let isDeckardAndroid = gaff.testIfAndroid(rachel) ``` +📝 Template Method +----------- + + The template method pattern defines the steps of an algorithm and allows the redefinition of one or more of these steps. In this way, the template method protects the algorithm, the order of execution and provides abstract methods that can be implemented by concrete types. + +### Example + +```swift +protocol Garden { + func prepareSoil() + func plantSeeds() + func waterPlants() + func prepareGarden() +} + +extension Garden { + + func prepareGarden() { + prepareSoil() + plantSeeds() + waterPlants() + } +} + +final class RoseGarden: Garden { + + func prepare() { + prepareGarden() + } + + func prepareSoil() { + print ("prepare soil for rose garden") + } + + func plantSeeds() { + print ("plant seeds for rose garden") + } + + func waterPlants() { + print ("water the rose garden") + } +} + +``` + +### Usage + +```swift + +let roseGarden = RoseGarden() +roseGarden.prepare() +``` + 🏃 访问者(Visitor) -------------- @@ -947,6 +1000,49 @@ CurrencyFactory.currency(for: .greece)?.code ?? noCurrencyCode CurrencyFactory.currency(for: .spain)?.code ?? noCurrencyCode CurrencyFactory.currency(for: .unitedStates)?.code ?? noCurrencyCode CurrencyFactory.currency(for: .uk)?.code ?? noCurrencyCode +``` + + 🔂 单态(Monostate) + ------------ + + 单态模式是实现单一共享的另一种方法。不同于单例模式,它通过完全不同的机制,在不限制构造方法的情况下实现单一共享特性。 + 因此,在这种情况下,单态会将状态保存为静态,而不是将整个实例保存为单例。 + [单例和单态 - Robert C. Martin](http://staff.cs.utu.fi/~jounsmed/doos_06/material/SingletonAndMonostate.pdf) + +### 示例: + +```swift +class Settings { + + enum Theme { + case `default` + case old + case new + } + + private static var theme: Theme? + + var currentTheme: Theme { + get { Settings.theme ?? .default } + set(newTheme) { Settings.theme = newTheme } + } +} +``` + +### 用法: + +```swift +import SwiftUI + +// 改变主题 +let settings = Settings() // 开始使用主题 .old +settings.currentTheme = .new // 改变主题为 .new + +// 界面一 +let screenColor: Color = Settings().currentTheme == .old ? .gray : .white + +// 界面二 +let screenTitle: String = Settings().currentTheme == .old ? "Itunes Connect" : "App Store Connect" ``` 🃏 原型(Prototype) diff --git a/source-cn/contentsReadme.md b/source-cn/contentsReadme.md index 372c3ad..268bf80 100644 --- a/source-cn/contentsReadme.md +++ b/source-cn/contentsReadme.md @@ -6,9 +6,9 @@ | [🐝 责任链 Chain Of Responsibility](#-责任链chain-of-responsibility) | [🌰 抽象工厂 Abstract Factory](#-抽象工厂abstract-factory) | [🔌 适配器 Adapter](#-适配器adapter) | | [👫 命令 Command](#-命令command) | [👷 生成器 Builder](#-生成器builder) | [🌉 桥接 Bridge](#-桥接bridge) | | [🎶 解释器 Interpreter](#-解释器interpreter) | [🏭 工厂方法 Factory Method](#-工厂方法factory-method) | [🌿 组合 Composite](#-组合composite) | -| [🍫 迭代器 Iterator](#-迭代器iterator) | [🃏 原型 Prototype](#-原型prototype) | [🍧 修饰 Decorator](#-修饰decorator) | -| [💐 中介者 Mediator](#-中介者mediator) | [💍 单例 Singleton](#-单例singleton) | [🎁 外观 Façade](#-外观facade) | -| [💾 备忘录 Memento](#-备忘录memento) | | [🍃 享元 Flyweight](#-享元flyweight) | +| [🍫 迭代器 Iterator](#-迭代器iterator) | [🔂 单态 Monostate](#-单态monostate) | [🍧 修饰 Decorator](#-修饰decorator) | +| [💐 中介者 Mediator](#-中介者mediator) | [🃏 原型 Prototype](#-原型prototype) | [🎁 外观 Façade](#-外观facade) | +| [💾 备忘录 Memento](#-备忘录memento) | [💍 单例 Singleton](#-单例singleton) | [🍃 享元 Flyweight](#-享元flyweight) | | [👓 观察者 Observer](#-观察者observer) | | [☔ 保护代理 Protection Proxy](#-保护代理模式protection-proxy) | | [🐉 状态 State](#-状态state) | | [🍬 虚拟代理 Virtual Proxy](#-虚拟代理virtual-proxy) | | [💡 策略 Strategy](#-策略strategy) | | | diff --git a/source-cn/creational/monostate.swift b/source-cn/creational/monostate.swift new file mode 100644 index 0000000..74898ef --- /dev/null +++ b/source-cn/creational/monostate.swift @@ -0,0 +1,39 @@ +/*: + 🔂 单态(Monostate) + ------------ + + 单态模式是实现单一共享的另一种方法。不同于单例模式,它通过完全不同的机制,在不限制构造方法的情况下实现单一共享特性。 + 因此,在这种情况下,单态会将状态保存为静态,而不是将整个实例保存为单例。 + [单例和单态 - Robert C. Martin](http://staff.cs.utu.fi/~jounsmed/doos_06/material/SingletonAndMonostate.pdf) + +### 示例: +*/ +class Settings { + + enum Theme { + case `default` + case old + case new + } + + private static var theme: Theme? + + var currentTheme: Theme { + get { Settings.theme ?? .default } + set(newTheme) { Settings.theme = newTheme } + } +} +/*: +### 用法: +*/ +import SwiftUI + +// 改变主题 +let settings = Settings() // 开始使用主题 .old +settings.currentTheme = .new // 改变主题为 .new + +// 界面一 +let screenColor: Color = Settings().currentTheme == .old ? .gray : .white + +// 界面二 +let screenTitle: String = Settings().currentTheme == .old ? "Itunes Connect" : "App Store Connect" From 461815b3152bd26698922d543f912e6611916d86 Mon Sep 17 00:00:00 2001 From: Binlogo Date: Fri, 30 Apr 2021 21:17:24 +0800 Subject: [PATCH 46/66] Translate template method pattern --- Design-Patterns-CN.playground.zip | Bin 25756 -> 40544 bytes .../Contents.swift | 49 ++++++++++++++++++ README-CN.md | 9 ++-- source-cn/behavioral/template_method.swift | 49 ++++++++++++++++++ source-cn/contentsReadme.md | 1 + source/contentsReadme.md | 9 ++-- 6 files changed, 109 insertions(+), 8 deletions(-) create mode 100644 source-cn/behavioral/template_method.swift diff --git a/Design-Patterns-CN.playground.zip b/Design-Patterns-CN.playground.zip index fc26705619aaf88de8255ffda5fe0b4e375943d8..73dcf613b81de2438630de80a36d9ac4958bd872 100644 GIT binary patch delta 22312 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 delta 8142 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 Date: Fri, 30 Apr 2021 16:14:41 +0200 Subject: [PATCH 47/66] Leverage GH Actions to generate .playground files Signed-off-by: Oktawian Chojnacki --- ...oy-chinese.yml => generate-playground.yml} | 36 ++++++++++++++++--- CONTRIBUTING.md | 8 +++++ GENERATE.md | 11 ------ PULL_REQUEST_TEMPLATE.md | 4 +-- 4 files changed, 42 insertions(+), 17 deletions(-) rename .github/workflows/{deploy-chinese.yml => generate-playground.yml} (54%) create mode 100644 CONTRIBUTING.md delete mode 100644 GENERATE.md diff --git a/.github/workflows/deploy-chinese.yml b/.github/workflows/generate-playground.yml similarity index 54% rename from .github/workflows/deploy-chinese.yml rename to .github/workflows/generate-playground.yml index 7c00059..82ad52f 100644 --- a/.github/workflows/deploy-chinese.yml +++ b/.github/workflows/generate-playground.yml @@ -1,17 +1,45 @@ -name: Deploy Chinese +name: Generate Playground Files # Controls when the action will run. Triggers the workflow on push or pull request # events but only for the master branch on: push: branches: [master] - pull_request: - branches: [master] # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: # This workflow contains a single job called "build" - build: + generate-english-playground: + # The type of runner that the job will run on + runs-on: macos-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v2 + + # Checkout to chinese branch & Generate Chinese + - name: Generate English Readme + run: | + ./generate-playground.sh + + # Commit + - name: Commit files + run: | + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + git commit -m "Generate Playground" + ## Push changes to master branch + - name: Push changes + uses: ad-m/github-push-action@master + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + branch: "master" + force: false + + # This workflow contains a single job called "build" + generate-chinese-playground-and-branch: + needs: generate-english-playground # The type of runner that the job will run on runs-on: macos-latest diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..e2386b4 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,8 @@ +How to contribute? +================== + +- You are awesome! +- Only editing files inside `source` is recommended, the rest is autogenerated and translated +- Run `generate-playground.sh` locally +- Opene the .playground locally and check if it works +- Please be patient and respectful to fellow contributors diff --git a/GENERATE.md b/GENERATE.md deleted file mode 100644 index 44d6937..0000000 --- a/GENERATE.md +++ /dev/null @@ -1,11 +0,0 @@ -How to generate playground and zip -================================== - -Do not change the `.playground` nor `README.md` manually! -Go to `/source` and edit *.swift files instead use Terminal to go to main directory use: - -```bash -./generate-playground.sh -``` - -👍 \ No newline at end of file diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md index ce7ed12..39a849c 100644 --- a/PULL_REQUEST_TEMPLATE.md +++ b/PULL_REQUEST_TEMPLATE.md @@ -1,3 +1,3 @@ +- [ ] Read [CONTRIBUTING.md]](https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/CONTRIBUTING.md]) - [ ] Added description -- [ ] Linked to or created issue -- [ ] Generated files as described [GENERATE.md](https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/GENERATE.md) \ No newline at end of file +- [ ] Linked to and/or created issue \ No newline at end of file From 2b611364e4526b9a4901a19d23ff43afc333bb28 Mon Sep 17 00:00:00 2001 From: Oktawian Chojnacki Date: Fri, 30 Apr 2021 17:02:11 +0200 Subject: [PATCH 48/66] CR improvements Signed-off-by: Oktawian Chojnacki --- .github/workflows/generate-playground.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/workflows/generate-playground.yml b/.github/workflows/generate-playground.yml index 82ad52f..1b30814 100644 --- a/.github/workflows/generate-playground.yml +++ b/.github/workflows/generate-playground.yml @@ -1,4 +1,4 @@ -name: Generate Playground Files +name: Generate Playground Files and READMES # Controls when the action will run. Triggers the workflow on push or pull request # events but only for the master branch @@ -9,7 +9,7 @@ on: # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: # This workflow contains a single job called "build" - generate-english-playground: + generate-playgrounds: # The type of runner that the job will run on runs-on: macos-latest @@ -18,10 +18,11 @@ jobs: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - uses: actions/checkout@v2 - # Checkout to chinese branch & Generate Chinese - - name: Generate English Readme + # Checkout & Generate + - name: Generate playgrounds and readmes run: | ./generate-playground.sh + ./generate-playground-cn.sh # Commit - name: Commit files @@ -38,8 +39,8 @@ jobs: force: false # This workflow contains a single job called "build" - generate-chinese-playground-and-branch: - needs: generate-english-playground + generate-chinese-branch: + needs: generate-playgrounds # The type of runner that the job will run on runs-on: macos-latest @@ -48,7 +49,7 @@ jobs: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - uses: actions/checkout@v2 - # Checkout to chinese branch & Generate Chinese + # Checkout & Generate - name: Generate Chinese Readme run: | ./generate-playground-cn.sh From d657167d2c4f049419ad032339564722e70e2775 Mon Sep 17 00:00:00 2001 From: Oktawian Chojnacki Date: Fri, 30 Apr 2021 17:26:38 +0200 Subject: [PATCH 49/66] Improve the job commit step Signed-off-by: Oktawian Chojnacki --- .github/workflows/generate-playground.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/generate-playground.yml b/.github/workflows/generate-playground.yml index 1b30814..89f3980 100644 --- a/.github/workflows/generate-playground.yml +++ b/.github/workflows/generate-playground.yml @@ -29,6 +29,10 @@ jobs: run: | git config --local user.email "action@github.com" git config --local user.name "GitHub Action" + git add Design-Patterns-CN.playground.zip + git add Design-Patterns.playground.zip + git add README.md + git add README-CN.md git commit -m "Generate Playground" ## Push changes to master branch - name: Push changes From 19c7c5359f472f875ea3bcf8ce6a9177e4fbe88e Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sat, 1 May 2021 01:37:17 +0000 Subject: [PATCH 50/66] Generate Playground --- Design-Patterns-CN.playground.zip | Bin 40544 -> 40544 bytes Design-Patterns.playground.zip | Bin 199169 -> 199169 bytes README.md | 9 +++++---- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Design-Patterns-CN.playground.zip b/Design-Patterns-CN.playground.zip index 73dcf613b81de2438630de80a36d9ac4958bd872..004aef26c003b59a6b4fdd286b637aa48c4173e1 100644 GIT binary patch delta 230 zcmaE`hv~r{Cf)#VW)?065Lm&pa3k+WZDt@nnNjCAnEtP052hV;qe1lM`MPI#zyf(z z`=Ao0lT)nKz>>YziDF>EkAY!e0k5FjjBr)4ArMtI1yE9f>OTvcocL{(czh~4D7a|AZOnxx7MHcMz) z9GEVi<_}hFFhhFsgJ}U^w(;~zu-y9Tbx^r%FgZ4<@=Y@j5j&KEW>`r9wwNw2(Xa!B*s5rGo}M2 zjixL7VbY&Iw}mlk`_;LO?~A}{j|(sbgVo9kGSy533(Z-?FM9UG5Lad?%$cdz=SivjFmr_%2{@^!L3maHLIumm;Sm-Phvk5x@Glq2k delta 310 zcmZpi!qYf~hd02RnT3l11b*ero5*X%45S*}wz@H{$_Fv0f6iyLVUEn5H~qjwMx$vz zm}I6m6fkmuM7H-9FlLFs<)+vDV3M0IFo}@^EE(F$c#{)k!gj-c#vUe^vIwxG^d!bV zT+HIW^QHqOjixL7VbY&Iw}mlk`_;LO?~A}{j|(sbgVo9kGSy53J7vxyCO5E&PZu#Q z4F(JKeq-_hE4TZ>Bt8B6Hzr>&&;2{o7npDcn6dH)QyB};H9^x4erJ-}Zu^sI4t!onaV)!+Wz1-QwtkdK{^w2GKjJLEEBT{I{<9!dcgny diff --git a/README.md b/README.md index 6a0bc4d..51f861d 100644 --- a/README.md +++ b/README.md @@ -26,13 +26,14 @@ print("Welcome!") | [🐝 Chain Of Responsibility](#-chain-of-responsibility) | [🌰 Abstract Factory](#-abstract-factory) | [🔌 Adapter](#-adapter) | | [👫 Command](#-command) | [👷 Builder](#-builder) | [🌉 Bridge](#-bridge) | | [🎶 Interpreter](#-interpreter) | [🏭 Factory Method](#-factory-method) | [🌿 Composite](#-composite) | -| [🍫 Iterator](#-iterator) | [🔂 Monostate](#-monostate) | [🍧 Decorator](#-decorator) | -| [💐 Mediator](#-mediator) | [🃏 Prototype](#-prototype) | [🎁 Façade](#-fa-ade) | +| [🍫 Iterator](#-iterator) | [🔂 Monostate](#-monostate) | [🍧 Decorator](#-decorator) | +| [💐 Mediator](#-mediator) | [🃏 Prototype](#-prototype) | [🎁 Façade](#-fa-ade) | | [💾 Memento](#-memento) | [💍 Singleton](#-singleton) | [🍃 Flyweight](#-flyweight) | -| [👓 Observer](#-observer) | | [☔ Protection Proxy](#-protection-proxy) | -| [🐉 State](#-state) | | [🍬 Virtual Proxy](#-virtual-proxy) | +| [👓 Observer](#-observer) | | [☔ Protection Proxy](#-protection-proxy) | +| [🐉 State](#-state) | | [🍬 Virtual Proxy](#-virtual-proxy) | | [💡 Strategy](#-strategy) | | | | [🏃 Visitor](#-visitor) | | | +| [📝 Template Method](#-template-method) | | | Behavioral From df2d836b30ee03ea03686d5897033871e1f8a5ac Mon Sep 17 00:00:00 2001 From: sookim <55218398+sookim-1@users.noreply.github.com> Date: Thu, 5 Aug 2021 10:30:38 +0900 Subject: [PATCH 51/66] Fix Prototype-Pattern SampleCode I want to modify the prototype pattern sample code. By default, the structure thinks that it does not need to use a prototype pattern because the values are copied. The sample code is structured, so I think it is right to change it to a class. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 51f861d..a743672 100644 --- a/README.md +++ b/README.md @@ -1058,7 +1058,7 @@ This practise is particularly useful when the construction of a new object is in ### Example ```swift -struct MoonWorker { +class MoonWorker { let name: String var health: Int = 100 From 3dde561c792cd92c655428c65d2a3b276518172d Mon Sep 17 00:00:00 2001 From: Sookim18 Date: Thu, 5 Aug 2021 10:53:01 +0900 Subject: [PATCH 52/66] Fix prototypesource code --- .../Pages/Creational.xcplaygroundpage/Contents.swift | 2 +- .../Pages/Creational.xcplaygroundpage/Contents.swift | 2 +- .../Pages/Creational.xcplaygroundpage/timeline.xctimeline | 6 ------ README-CN.md | 2 +- source-cn/creational/prototype.swift | 2 +- source/creational/prototype.swift | 2 +- 6 files changed, 5 insertions(+), 11 deletions(-) delete mode 100644 Design-Patterns.playground/Pages/Creational.xcplaygroundpage/timeline.xctimeline diff --git a/Design-Patterns-CN.playground/Pages/Creational.xcplaygroundpage/Contents.swift b/Design-Patterns-CN.playground/Pages/Creational.xcplaygroundpage/Contents.swift index e7d20d9..50394f8 100644 --- a/Design-Patterns-CN.playground/Pages/Creational.xcplaygroundpage/Contents.swift +++ b/Design-Patterns-CN.playground/Pages/Creational.xcplaygroundpage/Contents.swift @@ -236,7 +236,7 @@ let screenTitle: String = Settings().currentTheme == .old ? "Itunes Connect" : " ### 示例: */ -struct MoonWorker { +class MoonWorker { let name: String var health: Int = 100 diff --git a/Design-Patterns.playground/Pages/Creational.xcplaygroundpage/Contents.swift b/Design-Patterns.playground/Pages/Creational.xcplaygroundpage/Contents.swift index 4cad103..0cf5a4d 100644 --- a/Design-Patterns.playground/Pages/Creational.xcplaygroundpage/Contents.swift +++ b/Design-Patterns.playground/Pages/Creational.xcplaygroundpage/Contents.swift @@ -241,7 +241,7 @@ This practise is particularly useful when the construction of a new object is in ### Example */ -struct MoonWorker { +class MoonWorker { let name: String var health: Int = 100 diff --git a/Design-Patterns.playground/Pages/Creational.xcplaygroundpage/timeline.xctimeline b/Design-Patterns.playground/Pages/Creational.xcplaygroundpage/timeline.xctimeline deleted file mode 100644 index bf468af..0000000 --- a/Design-Patterns.playground/Pages/Creational.xcplaygroundpage/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/README-CN.md b/README-CN.md index e0c5a09..bf730b3 100644 --- a/README-CN.md +++ b/README-CN.md @@ -1054,7 +1054,7 @@ let screenTitle: String = Settings().currentTheme == .old ? "Itunes Connect" : " ### 示例: ```swift -struct MoonWorker { +class MoonWorker { let name: String var health: Int = 100 diff --git a/source-cn/creational/prototype.swift b/source-cn/creational/prototype.swift index c98ccf5..c9edbaa 100644 --- a/source-cn/creational/prototype.swift +++ b/source-cn/creational/prototype.swift @@ -6,7 +6,7 @@ ### 示例: */ -struct MoonWorker { +class MoonWorker { let name: String var health: Int = 100 diff --git a/source/creational/prototype.swift b/source/creational/prototype.swift index 7840489..e9ce828 100644 --- a/source/creational/prototype.swift +++ b/source/creational/prototype.swift @@ -7,7 +7,7 @@ This practise is particularly useful when the construction of a new object is in ### Example */ -struct MoonWorker { +class MoonWorker { let name: String var health: Int = 100 From 1473c978b9813ca1197c5a51378c357655321a87 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Thu, 5 Aug 2021 07:14:57 +0000 Subject: [PATCH 53/66] Generate Playground --- Design-Patterns-CN.playground.zip | Bin 40544 -> 40544 bytes Design-Patterns.playground.zip | Bin 199169 -> 199169 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/Design-Patterns-CN.playground.zip b/Design-Patterns-CN.playground.zip index 004aef26c003b59a6b4fdd286b637aa48c4173e1..628f865227b4ffebed29c3aea0a476ed859d4c95 100644 GIT binary patch delta 660 zcmaE`hv~r{CcXe~W)?065V&K>8oZJ3gSH@u5z+DO^ID*w79#_L@#F&uijxg=&ai-F zCh6LN>B$DxCX+d)%T2Zq;s6V5UZ8uL2O^bkwHKx)3L@8MogfA_7;F`kum&5f5Tp)K z;~jL15vI*#a%_kiFUY>_OZe<+fG)hcc|u4PXMM%Q(izJ>@?U%2ONEJf2dBA&lfJa{NbKPR?JFkm(|JhH2+Bc zJfb-3les{TIYW!p)VNElUR81YV4r@S^?v`sGY;P0Y9`<4I5WLp+deMTqHe*VkE;%S z6b@|_X4jfizd}pq>!y#-0}t(#*krii{NGI%lXLzjHRQAGZm#BbUGV+XDc@PuPtW}b z=a?6uV{dro4{~O6a!uecp1^W87+SG^y?m4%y D3b`9* delta 660 zcmaE`hv~r{CcXe~W)?065Lm&pFlZy+2W>$RBckKm=e0mVEk*_gIf4@4^8YA;Mp6hyAiIzbF zlL~B$Cm9wUD^U1!yiZPaUHqb^in~eIIb@F9X^T(#`_azPocI02MaQP@3f^M%Z04c) z6aD8b(yV7cSi$VDBKW21+Ewe?8yX5KV?X?rIK#6g<-B=k?}?h9J3c)QZGFtHC9_^j z#y&9AqHw{X`p#8{0`+C<hr?>OIo=l(s*XL{BdOt~+1`eBb(3F9-3FT zdHcN`XU?82~BA B9|r&c diff --git a/Design-Patterns.playground.zip b/Design-Patterns.playground.zip index ac901a9f11651222cbf9ecb24f5687dbdf147879..c997652de86ab08fb629e3d5c6c8cf5ccf27fd62 100644 GIT binary patch delta 682 zcmZpi!qYf~hcCdJnT3l11nyX}22bQOWdYHR?pxg%SLTD+)4$|1T0>X|Co&pN`@tkL zy`g}S3oNv~uYfUA1R*=U?gx|Hbb(2X9K0ZN7&8CuF6Lxl(BB^4%2>rwuV z-kUc2=)D zdMdE^#|-YQ>q{68T-v2q`RtzIcTc^A_6)^|(jVT<|8SSF{;Ix_v@z?B&zmlOXFR!2 z$@hlOW|m&dA7&R?%G(2Mb-I$DIPLmnb*uT&@%eXtu)3G@slERY$R2y=TJkz;|99v9 zl$~RBR;mulS6oplcj*5V4)YF|BlFfwc)Hhb@_&ZuymJ}tK>;o^JzyeZ?)EqRj29W< zQ4tP_ADKyvzaddI-L{3%aJs@DCjIGiTNtCZU!BYNz6hfHgaA_zM7f+GQ}slM;M_$_ zt`Nazi+3w1%(_PGmHk_Jc`g zdP4yt7g%U}UjbvL2tsyx-47n4&Ie0MPIX&t$mzMMm-|lsHuad7X`YbMU(Q?+F!{M?eh0zmszO&hB z{q?q^I8Wyr&%Lb+u2pjU4_CUQAS775$!XemE8l<2+g17*XEMRVJ{%GuGLsm8b4}Ol zXEdFz@P|o%`rH=AsO?whGQKZ@s5~LS6a-NzC&*Mi5h6Hu5tA!K@Yy1!CBYEEzHdz4 z5SIN9CaLM)zcKkjxE|k`KEox_(IR^D4< Date: Sat, 7 May 2022 19:33:43 +0200 Subject: [PATCH 54/66] Fix facade direct link in table of contents --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a743672..1b4086e 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ print("Welcome!") | [👫 Command](#-command) | [👷 Builder](#-builder) | [🌉 Bridge](#-bridge) | | [🎶 Interpreter](#-interpreter) | [🏭 Factory Method](#-factory-method) | [🌿 Composite](#-composite) | | [🍫 Iterator](#-iterator) | [🔂 Monostate](#-monostate) | [🍧 Decorator](#-decorator) | -| [💐 Mediator](#-mediator) | [🃏 Prototype](#-prototype) | [🎁 Façade](#-fa-ade) | +| [💐 Mediator](#-mediator) | [🃏 Prototype](#-prototype) | [🎁 Façade](#-façade) | | [💾 Memento](#-memento) | [💍 Singleton](#-singleton) | [🍃 Flyweight](#-flyweight) | | [👓 Observer](#-observer) | | [☔ Protection Proxy](#-protection-proxy) | | [🐉 State](#-state) | | [🍬 Virtual Proxy](#-virtual-proxy) | From 3d0e13d5be52fab213ba2efb88242ca10a597cb8 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Fri, 3 Feb 2023 09:07:47 +0000 Subject: [PATCH 55/66] Generate Playground --- Design-Patterns-CN.playground.zip | Bin 40544 -> 40544 bytes Design-Patterns.playground.zip | Bin 199169 -> 199169 bytes README.md | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/Design-Patterns-CN.playground.zip b/Design-Patterns-CN.playground.zip index 628f865227b4ffebed29c3aea0a476ed859d4c95..e301866c5c7c9271a17f5422319e0398a5508c55 100644 GIT binary patch delta 291 zcmaE`hv~r{CcXe~W)?065cuxl9JZ0~gSH@u5z+DO^ID*w79#_L@#F&uijxg=&ai-F zCh6L-`~cFE4XjNjb4-_;Y#+n{7TCN%_cRY!$>e;iy%2_hbrhJfxz9R53~VsiDkxzM zHdrA@9iqlN=oTZw=-3c7h_US8oZJ3gSH@u5z+DO^ID*w79#_L@#F&uijxg=&ai-F zCh6LN>B$DxCX+d)%T2Zq;s6V5UZ8uL2O^bkwHKx)3L@8MogfA_7;F`kum&5f5Tp)K z;~jL15vI*#a%_kiM7TX97-Hk*dy@>AAqs@2#X=Y*)BGR|!x>VOA505?a7?CGKo}dQ k*TST;AdLAlpiX|Co&pN`@tkL zy`g}S3oNv~uYfUA1R*=U?gx|Hbb(2X91!WSR>pK5xO6x~P-YV2Z;1Bkwk?c?(-rRiV6MG)mD1ek&#%H;%^swYAO=PqJ$g$O=d#Iz(BBG~th$s5A5|G^|R z{rfj2UkKOZJJV;lL^_zYebo;pe!2%ckN HHf9F^TuFA$ delta 309 zcmZpi!qYf~hcCdJnT3l11nyX}22bQOWdYHR?pxg%SLTD+)4$|1T0>X|Co&pN`@tkL zy`g}S3oNv~uYfUA1R*=U?gx|Hbb(2X91!WSR>pK5xO6x~P-YV2Z;1Bkwk?c?(-rRiV6MG)mD1ek&#%H;%^swYAO=PqJ$g$O=d#Iz(BBG~th$s5A5|G^|R z{rfj2UkKOZJJV;lL^_zYebo;pe!2%ckN HHf9F^s10n! diff --git a/README.md b/README.md index 1b4086e..a743672 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ print("Welcome!") | [👫 Command](#-command) | [👷 Builder](#-builder) | [🌉 Bridge](#-bridge) | | [🎶 Interpreter](#-interpreter) | [🏭 Factory Method](#-factory-method) | [🌿 Composite](#-composite) | | [🍫 Iterator](#-iterator) | [🔂 Monostate](#-monostate) | [🍧 Decorator](#-decorator) | -| [💐 Mediator](#-mediator) | [🃏 Prototype](#-prototype) | [🎁 Façade](#-façade) | +| [💐 Mediator](#-mediator) | [🃏 Prototype](#-prototype) | [🎁 Façade](#-fa-ade) | | [💾 Memento](#-memento) | [💍 Singleton](#-singleton) | [🍃 Flyweight](#-flyweight) | | [👓 Observer](#-observer) | | [☔ Protection Proxy](#-protection-proxy) | | [🐉 State](#-state) | | [🍬 Virtual Proxy](#-virtual-proxy) | From e8a0a2891bc0a1d378fdec00855d084a76e23333 Mon Sep 17 00:00:00 2001 From: Oktawian Chojnacki Date: Fri, 3 Feb 2023 10:18:51 +0100 Subject: [PATCH 56/66] Update CONTRIBUTING.md to reflect automated flow --- CONTRIBUTING.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e2386b4..c4b6fb1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,6 +3,8 @@ How to contribute? - You are awesome! - Only editing files inside `source` is recommended, the rest is autogenerated and translated +- Commit changes - Run `generate-playground.sh` locally -- Opene the .playground locally and check if it works +- Open the .playground locally and check if it works +- Remove the changes caused by `generate-playground.sh`, do not commit it! (_THIS IS A RECENT CHANGE_) - Please be patient and respectful to fellow contributors From c7108379838d47b0bf0bf7e4978a30e1a838f2cd Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Fri, 3 Feb 2023 09:19:15 +0000 Subject: [PATCH 57/66] Generate Playground --- Design-Patterns-CN.playground.zip | Bin 40544 -> 40544 bytes Design-Patterns.playground.zip | Bin 199169 -> 199169 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/Design-Patterns-CN.playground.zip b/Design-Patterns-CN.playground.zip index e301866c5c7c9271a17f5422319e0398a5508c55..00c8991d6a11da64e55cfe6405472b584e57b353 100644 GIT binary patch delta 205 zcmaE`hv~r{CY}IqW)?065J>mh$n!~?Dcx(5&L1E-`Javhh;q=40aBai>7L~QadWNq zLqyFcr&z0jWO}TV#6UtH0>eRE&!9VuFcq;OU=^()p>`mtJClr=K~jR#;z3l=v;YvL xKSO5n0|?V-dKE}y-Sm2hL=K3WI|D2zIWrx^YnoXKk&~G$It!$KbNZ~G%m5>WNb>*y delta 205 zcmaE`hv~r{CY}IqW)?065cuw~k>`^((|3po zbFKD+Cm)Id(1*Zq5Z5#44kJXL+2q&|HIUxckWf32)SXGj%pjG5 z)8au?(X;@NLj4&slOI5sM$@Z666>bdgDCwOIUs8846vZ&%yba1X=W)*ljtmv{>|yL Heli09OO94c diff --git a/Design-Patterns.playground.zip b/Design-Patterns.playground.zip index 5b7b00cce941eb53f3964134128ed2851f266dc2..cfeff375909c43cf5fbce3d4e4e22db480455afe 100644 GIT binary patch delta 264 zcmZpi!qYf~hbO?BnT3l11k$}G@|ZKFdo{Xlb!A+g4`faMl+S1jq74feBZ2hxo&v^f z5vYLi^tvBRa?=GSF>-*ULRuL!dEinCf0$&ZHxw{(fuy7+G5+OZN%wLNn{L~}XgD1x zsXu*g3uDywt8*FO7lAY#6JQDfDU}gqs+|ZDn7xR}9VGB%5!13@kU-BjCSMS3`vYk5 zcPPj0JJVOFU?xcQiXTjYOmJ1=zad)EelwMWWbglGYGnh-rZF+6fCSDkF`Kdj0P5yh ArvLx| delta 264 zcmZpi!qYf~hbO?BnT3l11ipJrj0Do#dkPq{ zMW6!4)9ZdP$xRoS#K-}X3Tb7`Sb A_W%F@ From 40826c18e55d4b68fb929d50d228a0f3067a5eec Mon Sep 17 00:00:00 2001 From: Oktawian Chojnacki Date: Wed, 5 Jul 2023 11:40:58 +0200 Subject: [PATCH 58/66] Update PULL_REQUEST_TEMPLATE.md --- PULL_REQUEST_TEMPLATE.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md index 39a849c..04d6063 100644 --- a/PULL_REQUEST_TEMPLATE.md +++ b/PULL_REQUEST_TEMPLATE.md @@ -1,3 +1,7 @@ -- [ ] Read [CONTRIBUTING.md]](https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/CONTRIBUTING.md]) -- [ ] Added description -- [ ] Linked to and/or created issue \ No newline at end of file +- [ ] Read [CONTRIBUTING.md](https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/CONTRIBUTING.md]) +- [ ] Only edited files inside `source` folder (IMPORTANT) and commited them with a meaningful message +- [ ] Ran `generate-playground.sh`, no errors +- [ ] Opened playground, it worked fine +- [ ] Did not commit the changes caused by `generate-playground.sh` +- [ ] Linked to and/or created issue +- [ ] Added a description to PR From b3795b0a7078b2cdd25bdc35a9c7ad9bee6f8541 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Wed, 5 Jul 2023 09:41:25 +0000 Subject: [PATCH 59/66] Generate Playground --- Design-Patterns-CN.playground.zip | Bin 40544 -> 40544 bytes Design-Patterns.playground.zip | Bin 199169 -> 199169 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/Design-Patterns-CN.playground.zip b/Design-Patterns-CN.playground.zip index 00c8991d6a11da64e55cfe6405472b584e57b353..d1371f72dca803422d96bbcc3854d8c5e2d30b41 100644 GIT binary patch delta 230 zcmaE`hv~r{Cf)#VW)?065YYC0x{>#zHZzc(%&7AlO#j!hXVwAo9d)BY^yc}xXL!I8 zc~<+N5~h<=tkuAhz1E3hV8M@pVPFBTpxcaaRk0xuRc#?5b|51*-<@Q{3^q$>S{#@z zp5_l$Z7@T6@`GssV7Bq}O0eAe>2*-KY%o1lO-pKn=n;A$?X4Lr&rvK~MgK0W)uw<`wq8M24V_+Cqz$@rBBV1K%2t-v|NQfO+_UEVE8I7j>V3L{M zP{7Cq64~Bcz?dZhmz!SqgGp|>z$8Wvuw-Z}V+IdQG6F0lJ&ExT7Yk5l*mT<#M#Jd} zf0*>A&uw9h+J1E|mp8I#EFEHT@u$GlSm;#t!LekU4e?wKK|7I!!D|qmmsf7)!Af1Uh87y>` IiP?l50K{KmtN;K2 From 7888f49b26635b8026d58c734daafd7e2d5070f5 Mon Sep 17 00:00:00 2001 From: "aakif.nadeem" Date: Tue, 26 Sep 2023 12:07:55 +0500 Subject: [PATCH 60/66] updated if let to latest swift --- source-cn/behavioral/chain_of_responsibility.swift | 2 +- source/behavioral/chain_of_responsibility.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source-cn/behavioral/chain_of_responsibility.swift b/source-cn/behavioral/chain_of_responsibility.swift index dbba65c..2ab3332 100644 --- a/source-cn/behavioral/chain_of_responsibility.swift +++ b/source-cn/behavioral/chain_of_responsibility.swift @@ -47,7 +47,7 @@ final class MoneyPile: Withdrawing { return true } - if let next = self.next { + if let next { return next.withdraw(amount: amount) } diff --git a/source/behavioral/chain_of_responsibility.swift b/source/behavioral/chain_of_responsibility.swift index cfe527c..e2dd24d 100644 --- a/source/behavioral/chain_of_responsibility.swift +++ b/source/behavioral/chain_of_responsibility.swift @@ -47,7 +47,7 @@ final class MoneyPile: Withdrawing { return true } - if let next = self.next { + if let next { return next.withdraw(amount: amount) } From 23b43a4829904102083fa1e8c28933bbce2e4385 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Thu, 18 Jan 2024 14:04:42 +0000 Subject: [PATCH 61/66] Generate Playground --- Design-Patterns-CN.playground.zip | Bin 40544 -> 40542 bytes Design-Patterns.playground.zip | Bin 199169 -> 199167 bytes README-CN.md | 2 +- README.md | 2 +- 4 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Design-Patterns-CN.playground.zip b/Design-Patterns-CN.playground.zip index d1371f72dca803422d96bbcc3854d8c5e2d30b41..ec93eeaba5ca6acfcd59dc6440ecbd4944ed3406 100644 GIT binary patch delta 5259 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 MoDe%U54bq_KW=HPpa1{> diff --git a/README-CN.md b/README-CN.md index bf730b3..ebea551 100644 --- a/README-CN.md +++ b/README-CN.md @@ -91,7 +91,7 @@ final class MoneyPile: Withdrawing { return true } - if let next = self.next { + if let next { return next.withdraw(amount: amount) } diff --git a/README.md b/README.md index a743672..13e3c5a 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,7 @@ final class MoneyPile: Withdrawing { return true } - if let next = self.next { + if let next { return next.withdraw(amount: amount) } From 8e1194c84323c75ffe84c05c0a907de396599e50 Mon Sep 17 00:00:00 2001 From: "aakif.nadeem" Date: Tue, 26 Sep 2023 12:24:57 +0500 Subject: [PATCH 62/66] update sorting inside source --- source-cn/contentsReadme.md | 3 +-- source/contentsReadme.md | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/source-cn/contentsReadme.md b/source-cn/contentsReadme.md index 5480d48..489f592 100644 --- a/source-cn/contentsReadme.md +++ b/source-cn/contentsReadme.md @@ -12,6 +12,5 @@ | [👓 观察者 Observer](#-观察者observer) | | [☔ 保护代理 Protection Proxy](#-保护代理模式protection-proxy) | | [🐉 状态 State](#-状态state) | | [🍬 虚拟代理 Virtual Proxy](#-虚拟代理virtual-proxy) | | [💡 策略 Strategy](#-策略strategy) | | | -| [🏃 访问者 Visitor](#-访问者visitor) | | | | [📝 模板方法 Templdate Method](#-template-method) | | | - +| [🏃 访问者 Visitor](#-访问者visitor) | | | diff --git a/source/contentsReadme.md b/source/contentsReadme.md index feefec3..6f1d4c6 100644 --- a/source/contentsReadme.md +++ b/source/contentsReadme.md @@ -12,6 +12,5 @@ | [👓 Observer](#-observer) | | [☔ Protection Proxy](#-protection-proxy) | | [🐉 State](#-state) | | [🍬 Virtual Proxy](#-virtual-proxy) | | [💡 Strategy](#-strategy) | | | -| [🏃 Visitor](#-visitor) | | | | [📝 Template Method](#-template-method) | | | - +| [🏃 Visitor](#-visitor) | | | From 87eb13fdc025d836565852022715220ab6f98bcc Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Thu, 18 Jan 2024 14:06:17 +0000 Subject: [PATCH 63/66] Generate Playground --- Design-Patterns-CN.playground.zip | Bin 40542 -> 40542 bytes Design-Patterns.playground.zip | Bin 199167 -> 199167 bytes README-CN.md | 3 +-- README.md | 3 +-- 4 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Design-Patterns-CN.playground.zip b/Design-Patterns-CN.playground.zip index ec93eeaba5ca6acfcd59dc6440ecbd4944ed3406..75ef26610ae9c76f54e5c18d60a9803cad1f3818 100644 GIT binary patch delta 198 zcmcb&hw0uPChh=lW)?065IDY(`?EIV@yY+S{{qRsI*yDdCLf$8JlVloW%7sVGLsvu zxfoAuo~wI~2PmCmbpS5y1r+YKP80(QybX*1a@>OMGQwq5CP#;;0R@{v!t5B2Z@xLn zgc+!xZ(0J7%%2trR+kGT^`}<@MOII50E@^@_M8y_WX+mU4J5^8W&p|hnPpHp;aNbr K%_*~fF#`b3i&Yo^ delta 198 zcmcb&hw0uPChh=lW)?065SY4=`?EIV)XD#~{{qRsI*vf{;56aM4%RA@KTMaI++fYc zICb+}-E%xZi5#l~aA_}~aJO}$7*ODCU<8ok7Ic>pE~_#*Iz$a9*c1|G2c&LJGGPYF z@l8trlKImD!Rm5>r2h13Ah~*a16V|MvgeEdAZykPkf_+q3?NxQvkWRHJPRndIc3%_ FW&j`9P*?x} diff --git a/Design-Patterns.playground.zip b/Design-Patterns.playground.zip index e0e23bb900d782b316ae0281716c4a2a75423283..95adaeb7938f697a371b3bfebc6772408f320db1 100644 GIT binary patch delta 281 zcmexAndkpx9_|2dW)?065I8=O+k)}<^oNU>gd4-RhBMC02l77VGuknpm~K$O7{z#E zdv^h2mI#DvGCkoZlg#vn0!A*NL|`jp77t9~!$d|kpqTh1#(!Ka#|w-irW^D#8cqia z%S`v1$e6qR@?6IEMSLI`u*G0vvLmbF^!ZH8^3w$bnK&4aZgd4-RhBMC02l77VGuiU=klDGO7W^#3wQS<6@awU=%Ukpr6rjI#5_< zy5B^`-0hd=GQKb31Id6b1{0GVSrw#$*j-Tm4{?o&NP3lP{3%{GI6=L?{bL0o^0Kea8 Date: Sun, 2 Jun 2024 22:06:50 +0800 Subject: [PATCH 64/66] Add CONTRIBUTING-CN.md --- CONTRIBUTING-CN.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 CONTRIBUTING-CN.md diff --git a/CONTRIBUTING-CN.md b/CONTRIBUTING-CN.md new file mode 100644 index 0000000..9e3b74d --- /dev/null +++ b/CONTRIBUTING-CN.md @@ -0,0 +1,19 @@ +如何贡献(中文版)? +================== + +- 你很棒! +- 仅建议编辑`source-cn`目录中的文件,其余内容是自动生成的并已翻译 +- 提交更改 +- 本地运行`generate-playground-cn.sh` +- 本地打开`Design-Patterns-CN.playground`文件并检查是否正常运行 +- 删除`generate-playground.sh`引起的更改,不要提交它!(_这是最近的更改_) +- 请耐心尊重其他贡献者 + +分支说明 +================== + +英文原上游主仓库已与中文版[统一维护](https://github.com/ochococo/Design-Patterns-In-Swift/pull/93): +- master 为主维护分支 +- chinese 分支仅为方便展示,将 README.md 显示为中文版本,由 GitHub Action 自动驱动 + +因此,直接将 PR 提交至[原始仓库](https://github.com/ochococo/Design-Patterns-In-Swift) master 主分支即可。 From 7d142dd1163cf97d38be300ccc040e736e9bca96 Mon Sep 17 00:00:00 2001 From: Binlogo Date: Sun, 2 Jun 2024 22:39:34 +0800 Subject: [PATCH 65/66] Fix link not found issue: GENERATE.md -> CONTRIBUTING.md - add CONTRIBUTING-CN.md for Chinese contributor --- source-cn/Index/header.md | 5 +++++ source/Index/header.md | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/source-cn/Index/header.md b/source-cn/Index/header.md index 1c42c6f..172eeb0 100644 --- a/source-cn/Index/header.md +++ b/source-cn/Index/header.md @@ -7,3 +7,8 @@ 👷 源项目由 [@nsmeme](http://twitter.com/nsmeme) (Oktawian Chojnacki) 维护。 🇨🇳 中文版由 [@binglogo](https://twitter.com/binglogo) 整理翻译。 + +🚀 如何由源代码,并生成 README 与 Playground 产物,请查看: +- [CONTRIBUTING.md](https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/CONTRIBUTING.md) +- [CONTRIBUTING-CN.md](https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/CONTRIBUTING-CN.md) + diff --git a/source/Index/header.md b/source/Index/header.md index 1c5bc49..2c48e66 100644 --- a/source/Index/header.md +++ b/source/Index/header.md @@ -10,4 +10,4 @@ A short cheat-sheet with Xcode 10.2 Playground ([Design-Patterns.playground.zip] 👷 中文版由 [@binglogo](https://twitter.com/binglogo) (棒棒彬) 整理翻译。 -🚀 How to generate README, Playground and zip from source: [GENERATE.md](https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/GENERATE.md) +🚀 How to generate README, Playground and zip from source: [CONTRIBUTING.md](https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/CONTRIBUTING.md) From 81264fefaaf0b8e867e018e073bb9dc71e63269a Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Wed, 3 Jul 2024 05:39:49 +0000 Subject: [PATCH 66/66] Generate Playground --- Design-Patterns-CN.playground.zip | Bin 40542 -> 40661 bytes Design-Patterns.playground.zip | Bin 199167 -> 199171 bytes README-CN.md | 5 +++++ README.md | 2 +- 4 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Design-Patterns-CN.playground.zip b/Design-Patterns-CN.playground.zip index 75ef26610ae9c76f54e5c18d60a9803cad1f3818..a582e54354ceea7c3410f0e5d74724b88233f5c4 100644 GIT binary patch delta 942 zcmcb&hw18GCf)#VW)?065cr|5N|;W*KSO46gEbdeL9cbZ7+B(cV3;6KM}&z@j>aVTMqq^a!&2xIP>ZY zqvI(lF~#!!=KA#f`ZeJ~Z_?D`;vYQtlKi1)^7U1kyE;0<7D?@0Q!=G)VV6OM%;#Uh z|L*ekmz{6?{rWa`1^+PjOlr@cRSbeeU+L;s}( z7pl)^%Rg#eQt{l~`c2O!3)Xf<_8pq@WgpLm#Gvkjw>>Afe`hez^_gKH7-ID=(f*T} zn#%`iL^1;)WAumB_zZSl%_V{o@B%fPFw=h;=pv_G=Fef(wiYY`QEeu zFxzl?C0K6l^g5_qHkh6>qY_L@%uM4$O?Q)fW@bW_N;6FenH-?2HraZXh5|^{_9c9F zHNfP5Rg!_h51b1a7=VeDVM*gVh{EU)naLBTOHIB%OOEMU{G>VNlg(y3F)o?>e|Gd_ zySZ$W3#PD5elS~(Nh)#DoJCAKCQKI4QJ7pifp_xj$y}3f&yi#L4-?{^e13w|WQVyL kOmP#Tsz5>#lh;q=n!J6k7SnNbVWr6)^90zOCxhGt0HQmsMgRZ+ delta 769 zcmcb*m+9UfCf)#VW)?065IA07w2}9tHZzc(%&7AlO#j!hXFdVsJL*P*=*{zW&+vdH z@~rkjB}^y3m?1a$LkI_0L9cbZ7+B(cV3;6KN5nBHo5$sh3=Bd{3=E!=KgKIgF3@G0 zTpOfXpF7dl`>=t;@%KMP4#q|$t`*mBQt)HZ*Lq`Nb0q5a4pYs{R~IJpUHsXU_hJu^ z8f$Cpnl9$}Z7ZYsq+ zEr^k7o_Cw0FQ0vGt-;UtOb#c`t`NKCQ6*To&M0ZA@#p$Ukq**Qi_Ib@nr+;v@?y^H zYb`p)AyZ7wlvdx|7P2hhQ0O7mRw<*x5QI)K-dQ#kFRtBmHOmz+WiH%xfGqC>Dza_&08B~LbTG?$&W z-%)d0%k|dYw2F6$@9RI_vcJ#$?R00Ar0`k?(_h7x6MvhFE{xA+oqG4d*1P*x9y=7m z)%J5w9&bb7jMvugdyl8DFP!n`$RvZcuQFtV+qjaB>@B*R&HtGvSn&9invV-=UzwM+ zRZKIEepq%%pE+m7ltK$>+t54g4JQpA9_onCstUjBm|pF|G9MD}!t diff --git a/Design-Patterns.playground.zip b/Design-Patterns.playground.zip index 95adaeb7938f697a371b3bfebc6772408f320db1..e4163def33dcf4b4f8867f3267589689b72baef7 100644 GIT binary patch delta 1034 zcmexAnWuRQ4{v}sGYc032>j4_JdxLo8Avs{ZFOT@l@DT0|D4Zg17_@-$Y?Zue*vS+ z^o9aPE|Adn-U7x95rkyIPbMVE;8w;A9++eVSiR&V#y?yvK%EiO4f+`kr+=6TG|g`! zWA66La~a9a$Bp&u3zmpDrNC#32Zh+_~m;?|nuFhB#&h2Dj;q1&k`w zeFd2;>vJxzsxH{QMVrf;fAYV=i1$-I7zFoW$webz-ZD!X}%ilG9J9E2zAglGIgjI9}CU z|EItvHnl*hM%6is(uK|mdNp#|q+}g>cxzR?Y@4QS$JTnSCoFRcA0Lda`0%;-g1yMk zb(0mIEfZ&%HLWhEvulMxjB%>3*O!^6n2rh^eIus$f%()bDi3_(?^v^C$Q% zXMVi-^5gQd+JArF9)9!n#fH;2NkY{o?hH6*OOoGIr*lf$)qsB-0wP$x;Gv4ETVsVcsr`Lbl#dgaurT`|Gko0uX-%ypQznRJ)iBRz;lhpQ~znL=G zz{*mYn3H)?lG*gDOw6rJfx^=p*_rL9%ds#^Ouxgz%rkvIGqW7i5rl98la38U&3+bU zccvu>j_mYv1x#|&>;EzFOz&f5mSaqq&dA2BIsFe%|pp;2sA;=!D>9*|5Qqx~^GV`(ZFJc1f1OQM#uZ{o! delta 1120 zcmZpk!t;MJ4{v}sGYc032plgkn#gO$45S*}wz@H{$_Fv0f6iyLVLkz5?3>7FG<|;o zqs;V%0!A*7(DvQ}#tadJWWx_8x#-ps5kl4f+`k zr+=6TGVLdm@bn4&j8WS!&t-gH#0QcFy9Z26c4SqYE?>aNHl3fDSsZM&AV|fs8|9mC zGcquQF*7i@O=m1%Q~@baon9o!BvK!<{p0zAySA{lE^YTLGn;8PlhatgtxC%_VsB(1 ze_YjvM~;Gl0RkTnuh=d3Td>CS#=A|+<$R1joaq1gw=!St#W#uD0%2-gZ8CupsgBQF z)ruAd^f+qWSoehG;jI1V*2RBFT*Gg6l}*u))&2Z3CxsB9;0lS?8ymD={|l8!`=el3 zzbhoUz-=vi{=0+v=N$iU)G3=QvT?&+1%o}Ggq5@wU*ZzZHd=Y1zf|sp#Z|+-2f3z} zhgbTxC_JC`Z_Oj^pmnc}ue~fuC@HJ@(|7Ip{rh%4@$%>A*~ae3kc|m2J5^$G{T|nE z>F-YY8(uz7p1yJO<;m*}Osf2kaER?(87(LKC84C=`R1Io3tp3yg1&bwn3$s|KIixE z6WS+5d4l#Xuh^sie9rTE>H7A9kt(5+Ub^TD>3lvLm^5c!t>gXq^6z73?E7U@{V(O) z=im4H)%WxDXFW1+FK`cUkP=$h@=#*|Z%Jk4j5%VaLTYZ$6G}6a92@i6XFm+9S6}kr z|H6LnoIG2-8(t3s)g1g2F3547ju3YvoXstGEV=<#vCv`o)c*CC6GW4NMI7vi+m(oZ8@1Grl0%6 z#54T`JF^^9bOE|tJO{G}Q_upCuHMv<@MxJe_YL(2ztcniVXo~T`{ec diff --git a/README-CN.md b/README-CN.md index bda51be..2a3206c 100644 --- a/README-CN.md +++ b/README-CN.md @@ -9,6 +9,11 @@ 🇨🇳 中文版由 [@binglogo](https://twitter.com/binglogo) 整理翻译。 +🚀 如何由源代码,并生成 README 与 Playground 产物,请查看: +- [CONTRIBUTING.md](https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/CONTRIBUTING.md) +- [CONTRIBUTING-CN.md](https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/CONTRIBUTING-CN.md) + + ```swift print("您好!") diff --git a/README.md b/README.md index 8dec0c1..09f58c2 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ A short cheat-sheet with Xcode 10.2 Playground ([Design-Patterns.playground.zip] 👷 中文版由 [@binglogo](https://twitter.com/binglogo) (棒棒彬) 整理翻译。 -🚀 How to generate README, Playground and zip from source: [GENERATE.md](https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/GENERATE.md) +🚀 How to generate README, Playground and zip from source: [CONTRIBUTING.md](https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/CONTRIBUTING.md) ```swift