行爲型模式 | 建立型模式 | 結構型模式javascript
在軟件工程中, 行爲型模式爲設計模式的一種類型,用來識別對象之間的經常使用交流模式並加以實現。如此,可在進行這些交流活動時加強彈性。java
來源: 維基百科git
責任鏈模式在面向對象程式設計裏是一種軟件設計模式,它包含了一些命令對象和一系列的處理對象。每個處理對象決定它能處理哪些命令對象,它也知道如何將它不能處理的命令對象傳遞給該鏈中的下一個處理對象。github
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
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.nextPile {
return next.canWithdraw(amount: amount)
}
return false
}
}
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,
ten: MoneyPile) {
self.hundred = hundred
self.fifty = fifty
self.twenty = twenty
self.ten = ten
}
func canWithdraw(amount: Int) -> String {
return "可否取現:\(self.startPile.canWithdraw(amount: amount))"
}
}複製代碼
// 建立一系列的錢堆,並將其連接起來: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)
// 建立 ATM 實例
var atm = ATM(hundred: hundred, fifty: fifty, twenty: twenty, ten: ten)
atm.canWithdraw(amount: 310)
atm.canWithdraw(amount: 100)
atm.canWithdraw(amount: 165)
atm.canWithdraw(amount: 30)複製代碼
更多示例:Design Patterns in Swift算法
命令模式是一種設計模式,它嘗試以對象來表明實際行動。命令對象能夠把行動(action) 及其參數封裝起來,因而這些行動能夠被:express
protocol DoorCommand {
func execute() -> String
}
class OpenCommand: DoorCommand {
let doors: String
required init(doors: String) {
self.doors = doors
}
func execute() -> String {
return "\(doors)打開了"
}
}
class CloseCommand: DoorCommand {
let doors: String
required init(doors: String) {
self.doors = doors
}
func execute() -> String {
return "\(doors)關閉了"
}
}
class ZhimaDoorsOperations {
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()
}
}複製代碼
let zhimaDoors = "芝麻門"
let doorModule = ZhimaDoorsOperations(doors: zhimaDoors)
doorModule.open()
doorModule.close()複製代碼
給定一種語言,定義他的文法的一種表示,並定義一個解釋器,該解釋器使用該表示來解釋語言中句子。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)
}
}複製代碼
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))
context.assign(expression: a, value: 2)
context.assign(expression: b, value: 1)
context.assign(expression: c, value: 3)
var result = expression.evaluate(context)複製代碼
更多示例:Design Patterns in 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)
}
}複製代碼
let greatNovellas = Novellas(novellas: [Novella(name:"紅樓夢")])
for novella in greatNovellas {
print("我讀了\(novella.name)")
}複製代碼
用一箇中介者對象封裝一系列的對象交互,中介者使各對象不須要顯示地相互做用,從而使耦合鬆散,並且能夠獨立地改變它們之間的交互。數據結構
struct Programmer {
let name: String
init(name: String) {
self.name = name
}
func receive(message: String) {
print("\(name) 收到消息:\(message)")
}
}
protocol MessageSending {
func send(message: String)
}
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)
}
}
}複製代碼
func spamMonster(message: String, worker: MessageSending) {
worker.send(message: message)
}
let messagesMediator = MessageMediator()
let user0 = Programmer(name: "Linus Torvalds")
let user1 = Programmer(name: "Dylan Wang")
messagesMediator.add(recipient: user0)
messagesMediator.add(recipient: user1)
spamMonster(message: "我但願添加您到個人職業網絡", worker: messagesMediator)複製代碼
在不破壞封裝性的前提下,捕獲一個對象的內部狀態,並在該對象以外保存這個狀態。這樣就能夠將該對象恢復到原先保存的狀態
typealias Memento = NSDictionary
// 發起人(Originator)
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 = chapter
}
init?(memento: Memento) {
guard let mementoChapter = memento[Keys.chapter] as? String,
let mementoWeapon = memento[Keys.weapon] as? String else {
return nil
}
self.chapter = mementoChapter
self.weapon = mementoWeapon
}
var memento: Memento {
return [Keys.chapter: chapter,
Keys.weapon: weapon]
}
}
// 管理者(Caretaker)
enum CheckPoint {
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
}
}複製代碼
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") {
let finalState = GameState(memento: memento)
dump(finalState)
}複製代碼
一個目標對象管理全部相依於它的觀察者對象,而且在它自己的狀態改變時主動發出通知
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.")
}
}
}複製代碼
var observer = Observer()
var testChambers = TestChambers()
testChambers.observer = observer
testChambers.testChamberNumber += 1複製代碼
在狀態模式中,對象的行爲是基於它的內部狀態而改變的
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 }
}複製代碼
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)複製代碼
對象有某個行爲,可是在不一樣的場景中,該行爲有不一樣的實現算法。策略模式:
protocol PrintStrategy {
func print(_ string: String) -> String
}
final class Printer {
private let strategy: PrintStrategy
init(strategy: PrintStrategy) {
self.strategy = strategy
}
func print(_ string: String) -> String {
return self.strategy.print(string)
}
}
final class UpperCaseStrategy: PrintStrategy {
func print(_ string: String) -> String {
return string.uppercased()
}
}
final class LowerCaseStrategy: PrintStrategy {
func print(_ string: String) -> String {
return string.lowercased()
}
}複製代碼
var lower = Printer(strategy: LowerCaseStrategy())
lower.print("0 tempora, o mores")
var upper = Printer(strategy: UpperCaseStrategy())
upper.print("0 tempora, o mores")複製代碼
封裝某些做用於某種數據結構中各元素的操做,它能夠在不改變數據結構的前提下定義做用於這些元素的新的操做。
protocol PlanetVisitor {
func visit(planet: PlanetAlderaan)
func visit(planet: PlanetCoruscant)
func visit(planet: PlanetTatooine)
func visit(planet: MoonJedah)
}
protocol Planet {
func accept(visitor: PlanetVisitor)
}
class MoonJedah: Planet {
func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) }
}
class PlanetAlderaan: Planet {
func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) }
}
class PlanetCoruscant: Planet {
func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) }
}
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: MoonJedah) { name = "Jedah" }
}複製代碼
let planets: [Planet] = [PlanetAlderaan(), PlanetCoruscant(), PlanetTatooine(), MoonJedah()]
let names = planets.map { (planet: Planet) -> String in
let visitor = NameVisitor()
planet.accept(visitor: visitor)
return visitor.name
}
names複製代碼