在 Swift 5.0 中实现的设计模式
一份简短的速查表,附带 Xcode 10.2 Playground(Design-Patterns.playground.zip)。
🇨🇳中文版
👷 项目发起人:@nsmeme (Oktawian Chojnacki)
👷 中文版由 @binglogo (棒棒彬) 整理翻译。
🚀 如何从源码生成 README、Playground 和 zip:CONTRIBUTING.md
print("Welcome!")
目录
| 行为型 | 创建型 | 结构型 |
|---|---|---|
| 🐝 责任链模式 | 🌰 抽象工厂模式 | 🔌 适配器模式 |
| 👫 命令模式 | 👷 建造者模式 | 🌉 桥接模式 |
| 🎶 解释器模式 | 🏭 工厂方法模式 | 🌿 组合模式 |
| 🍫 迭代器模式 | 🔂 单态模式 | 🍧 装饰器模式 |
| 💐 中介者模式 | 🃏 原型模式 | 🎁 外观模式 |
| 💾 备忘录模式 | 💍 单例模式 | 🍃 享元模式 |
| 👓 观察者模式 | ☔ 保护代理模式 | |
| 🐉 状态模式 | 🍬 虚拟代理模式 | |
| 💡 策略模式 | ||
| 📝 模板方法模式 | ||
| 🏃 访客 |
行为型
在软件工程中,行为型设计模式是识别对象之间常见通信模式并实现这些模式的设计模式。通过这种方式,这些模式提高了执行此类通信的灵活性。
来源: wikipedia.org
🐝 责任链
责任链模式用于处理各种请求,每个请求可能由不同的处理者来处理。
示例:
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 {
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)
}
}
用法
// 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
命令模式用于在命令对象中表达一个请求,包括要执行的调用及其所有必需参数。该命令可以立即执行,也可以保留以供后续使用。
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()
}
}
用法:
let podBayDoors = "Pod Bay Doors"
let doorModule = HAL9000DoorsOperations(doors:podBayDoors)
doorModule.open()
doorModule.close()
🎶 解释器
解释器模式用于评估语言中的句子。
示例
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)) // 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)
🍫 迭代器
迭代器模式用于为遍历聚合对象中的项目集合提供标准接口,而无需了解其底层结构。
示例:
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: "The Mist")] )
for novella in greatNovellas {
print("I've read: \(novella)")
}
💐 Mediator
Mediator 模式用于降低相互通信的类之间的耦合度。类之间不再直接通信(从而无需了解彼此的实现细节),而是通过一个 Mediator 对象发送消息。
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)
}
}
}
用法
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
备忘录模式用于捕获对象的当前状态,并以一种稍后能够恢复该状态且不破坏封装规则的方式对其进行存储。
示例
typealias Memento = [String: String]
发起者
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)
}
}
用法
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)
}
👓 观察者
观察者模式用于允许一个对象发布其状态的变化。 其他对象订阅以立即获知任何变化。
示例
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 observerInstance = Observer()
var testChambers = TestChambers()
testChambers.observer = observerInstance
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)
💡 策略
策略模式用于创建一组可互换的算法,从中在运行时选择所需的处理过程。
示例
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)
}
}
用法
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)
📝 模板方法
模板方法模式定义了算法的步骤,并允许重新定义其中一个或多个步骤。通过这种方式,模板方法保护了算法、执行顺序,并提供了可由具体类型实现的抽象方法。
示例
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")
}
}
用法
let roseGarden = RoseGarden()
roseGarden.prepare()
🏃 访问者
访问者模式用于将一组相对复杂的结构化数据类与可对这些数据类所持有的数据执行的功能分离开来。
示例
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" }
}
用法
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
Creational
在软件工程中,创建型设计模式是处理对象创建机制的设计模式,旨在以适合特定情境的方式创建对象。对象创建的基本形式可能导致设计问题或增加设计的复杂性。创建型设计模式通过某种方式控制对象创建来解决这一问题。
来源: wikipedia.org
🌰 Abstract Factory
抽象工厂模式用于向客户端提供一组相关或相互依赖的对象。 工厂创建的“对象族”在运行时确定。
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"])
}
}
抽象工厂
enum BurgerFactoryType: BurgerMaking {
case bigKahuna
case jackInTheBox
func make() -> BurgerDescribing {
switch self {
case .bigKahuna:
return BigKahunaBurger().make()
case .jackInTheBox:
return JackInTheBox().make()
}
}
}
用法
let bigKahuna = BurgerFactoryType.bigKahuna.make()
let jackInTheBox = BurgerFactoryType.jackInTheBox.make()
👷 建造者
建造者模式用于创建具有必须按相同顺序或使用特定算法创建的组成部分的复杂对象。 外部类控制构建算法。
示例
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))"
}
}
用法
let empire = DeathStarBuilder { builder in
builder.x = 0.1
builder.y = 0.2
builder.z = 0.3
}
let deathStar = DeathStar(builder:empire)
🏭 工厂方法
工厂模式用于替代类构造函数,将对象生成过程抽象化,使得实例化对象的类型可以在运行时确定。
示例
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
}
}
}
用法
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
🔂 单态
单态模式是实现单例性的另一种方式。它通过完全不同的机制运作,在不施加结构性约束的情况下强制实现单例性行为。 在这种情况下,单态将状态保存为静态,而不是将整个实例作为单例。 SINGLETON and MONOSTATE - Robert C. Martin
示例:
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
// When change the theme
let settings = Settings() // Starts using theme .old
settings.currentTheme = .new // Change theme to .new
// On screen 1
let screenColor: Color = Settings().currentTheme == .old ? .gray : .white
// On screen 2
let screenTitle: String = Settings().currentTheme == .old ? "Itunes Connect" : "App Store Connect"
🃏 原型
原型模式通过复制现有对象的所有属性来实例化一个新对象,从而创建一个独立的克隆。 当新对象的构建效率低下时,这种实践特别有用。
示例
class MoonWorker {
let name: String
var health: Int = 100
init(name: String) {
self.name = name
}
func clone() -> MoonWorker {
return MoonWorker(name: name)
}
}
用法
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
💍 单例
单例模式确保某个特定类的对象只被创建一次。 对单例类对象的所有后续引用都指向同一个底层实例。 很少有应用场景需要它,不要过度使用此模式!
示例:
final class ElonMusk {
static let shared = ElonMusk()
private init() {
// Private initialization to ensure just one instance is created.
}
}
用法:
let elon = ElonMusk.shared // There is only one Elon Musk folks.
结构性
在软件工程中,结构性设计模式是通过识别一种简单的方式来实现实体之间的关系,从而简化设计的设计模式。
来源: wikipedia.org
🔌 Adapter
Adapter 模式用于通过用一个支持客户端所需接口的类来包装“被适配者”(adaptee),从而在两个原本不兼容的类型之间提供链接。
示例
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
}
}
适配器
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
}
}
用法
let target = OldDeathStarSuperlaserTarget(angleHorizontal: 14.0, angleVertical: 12.0)
let newFormat = NewDeathStarSuperlaserTarget(target)
newFormat.angleH
newFormat.angleV
🌉 桥接
桥接模式用于将类的抽象部分与其实现细节分离,提供在不修改抽象的情况下替换实现细节的手段。
示例
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")
}
}
用法
let tvRemoteControl = RemoteControl(appliance: TV())
tvRemoteControl.turnOn()
let fancyVacuumCleanerRemoteControl = RemoteControl(appliance: VacuumCleaner())
fancyVacuumCleanerRemoteControl.turnOn()
🌿 组合
组合模式用于创建相关对象的层次化、递归树形结构,其中结构的任何元素都可以以标准方式访问和利用。
示例
Component
protocol Shape {
func draw(fillColor: String)
}
叶片
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)")
}
}
复合
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)
}
}
}
用法:
var whiteboard = Whiteboard(Circle(), Square())
whiteboard.draw(fillColor: "Red")
🍧 装饰器
装饰器模式通过在运行时将对象包装在装饰器类的对象中,来扩展或修改对象的功能。 这提供了一种使用继承来修改行为的灵活替代方案。
示例
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"]
}
}
用法:
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)")
🎁 外观
外观模式用于为更复杂的子系统定义一个简化的接口。
示例
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)
}
}
}
用法
let storage = Defaults()
// Store
storage["Bishop"] = "Disconnect me. I’d rather be nothing"
// Read
storage["Bishop"]
🍃 享元模式
享元模式通过与其他相似对象尽可能多地共享来最小化内存使用或计算开销。
示例
// 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)")
}
}
}
用法
let coffeeShop = CoffeeShop(menu: Menu())
coffeeShop.takeOrder(origin: "Yirgacheffe, Ethiopia", table: 1)
coffeeShop.takeOrder(origin: "Buziraguhindwa, Burundi", table: 3)
coffeeShop.serve()
☔ 保护代理
代理模式用于提供一个替代对象或占位对象,该对象引用一个底层对象。 保护代理用于限制访问。
示例
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)
}
}
用法
let computer = CurrentComputer()
let podBay = "Pod Bay Doors"
computer.open(doors: podBay)
computer.authenticate(password: "pass")
computer.open(doors: podBay)
🍬 虚拟代理
代理模式用于提供一个替代对象或占位对象,该对象引用一个底层对象。 虚拟代理用于按需加载对象。
示例
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()
}
}
用法
let humanInterface = HEVSuitHumanInterface()
humanInterface.administerMorphine()