preface
This is a subjective article with simple text explanation. The purpose of this article is to share knowledge within the team and make colleagues who do not know the design pattern familiar with these new words quickly. So this article is suitable for those who know Swift grammar and want to quickly understand what the 23 design patterns are about.
Pre-knowledge of UML those lines
The basic structure
- The metaphor reminds me of something
- Official definition original definition
- UML is not the original UML only retains what I think is the core
- Code Swift implementation, this is the ontology
- The tutorial assumes you’ve seen some scattered comments on the code
directory
- Creational creates type 5
- Abstract Factory Abstract Factory pattern
- Builder mode
- Factory Method Indicates the Factory Method mode
- Prototype
- Singleton Singleton pattern
- Structural type 7
- Adapter Adapter mode
- Bridge Bridge mode
- Composite mode
- Decorator Decorator pattern
- Facade pattern
- Flyweight share mode
- Proxy mode
- Behavioral behavior 11
- Chain of responsibility mode
- Command Command mode
- Interpreter mode
- Iterator Indicates the Iterator mode
- Mediator mode
- Memento mode
- Observer mode
- State mode
- Strategy Mode
- Template Method Indicates the Template Method mode
- Visitor pattern
The factory pattern
The factory model, as the name suggests, is like a factory that produces the products you need
Pictures: http://cdn1.alphr.com/sites/alphr/files/2016/02/tesla_factory_tour_1.jpg
No Non – Factory Factory
The original problem that the factory problem is trying to solve.
protocol Product {}
class ConcreteProductA: Product {}
class ConcreteProductB: Product {}
class Client {
func createProduct(type: Int) -> Product {
if type == 0 {
return ConcreteProductA()}else {
return ConcreteProductB()}}}let c = Client(a)c.createProduct(type: 0) // get ConcreteProductA
Copy the code
As can be seen from the code and UML, in order to get ProductA, the caller Client relies on both Product, ConcreteProductA, and ConcreteProductB, and writes A method to create the Product himself.
Each time a new product is required, a change is made to the caller Client. It would be nice if this whole bunch of creation code could be removed, and simple factories emerged.
Simple Factory
One of the things that the simple factory does is move the Client’s creation work to another class.
protocol Product {}
class ConcreteProductA: Product {}
class ConcreteProductB: Product {}
class Client {
let s = Factory()}class Factory {
func createProduct(type: Int) -> Product {
if type == 0 {
return ConcreteProductA()}else {
return ConcreteProductB()}}}let c = Client(a)c.s.createProduct(type: 0) // get ConcreteProductA
Copy the code
Factory replaces Client’s dependency on a specific Product, so we no longer need to change the caller when the requirements change. This is an improvement, but it is inevitable that every change creates an if-else branch inside the createProduct method, which clearly violates the open and close principle.
To solve this problem, we introduce another pattern.
Factory Method
The official definition of
Define an interface to create an object and let subclasses decide which factory class to instantiate. The factory pattern delays the creation of the object until the subclass.
protocol Product {}
class ConcreteProductA: Product {}
class ConcreteProductB: Product {}
class Client {
let f = Factory()}class Factory {
func createProduct(a) -> Product? { return nil } // For inheritance
func createProduct(type: Int) -> Product? { // Used for invocation
if type == 0 {
return ConcreteFactoryA().createProduct()
} else {
return ConcreteFactoryB().createProduct()
}
}
}
class ConcreteFactoryA: Factory {
override func createProduct(a) -> Product? {
/ /... Product processing process
return ConcreteProductA()}}class ConcreteFactoryB: Factory {
override func createProduct(a) -> Product? {
/ /... Product processing process
return ConcreteProductB()}}let c = Client(a)c.f.createProduct(type: 0) // get ConcreteProductA
Copy the code
There are many different ways to implement a Factory method. For example, Factory keeps only a createProduct for subclasses to implement, and lets Client choose which specific Factory instance to generate. Or introduce an intermediate layer of FactoryMaker as a “simple factory” for a manufacturing plant. The approach I’ve taken here is Factory as both a Factory parent class that lets specific factories decide to produce products, and an interface class that lets clients select specific factories through dependency injection. My goal is to minimize Client dependencies without introducing a new middle tier.
The factory approach does two things on top of the simple factory:
- An additional layer of abstraction, postponing production to subclasses.
- Turn “the job of choosing how products are made” into “choosing which specific factories to make them.”
The contribution of the factory method is that while this is not perfect for avoiding an if-else extension, the scale of the extension is very limited (only a new class is required).
The factory approach focuses on solving the derivation problem of a single product line. What if there are multiple related product lines?
Abstract Factory
The official definition of
Provides an interface for creating a series of related or interdependent objects without specifying their concrete classes.
protocol ProductA {}
class ConcreteProductA1: ProductA {}
class ConcreteProductA2: ProductA {}
protocol ProductB {}
class ConcreteProductB1: ProductB {}
class ConcreteProductB2: ProductB {}
class Client {
let f = Factory()}class Factory {
func createProductA(a) -> ProductA? { return nil } // For inheritance
func createProductB(a) -> ProductB? { return nil } // For inheritance
func createProductA(type: Int) -> ProductA? { // Used for invocation
if type == 0 {
return ConcreteFactory1().createProductA()
} else {
return ConcreteFactory2().createProductA()
}
}
func createProductB(type: Int) -> ProductB? { // Used for invocation
if type == 0 {
return ConcreteFactory1().createProductB()
} else {
return ConcreteFactory2().createProductB()
}
}
}
class ConcreteFactory1: Factory {
override func createProductA(a) -> ProductA? {
/ /... Product processing process
return ConcreteProductA1()}override func createProductB(a) -> ProductB? {
/ /... Product processing process
return ConcreteProductB1()}}class ConcreteFactory2: Factory {
override func createProductA(a) -> ProductA? {
/ /... Product processing process
return ConcreteProductA2()}override func createProductB(a) -> ProductB? {
/ /... Product processing process
return ConcreteProductB2()}}let c = Client(a)c.f.createProductA(type: 0) // get ConcreteProductA1
c.f.createProductA(type: 1) // get ConcreteProductA2
c.f.createProductB(type: 0) // get ConcreteProductB1
c.f.createProductB(type: 1) // get ConcreteProductB2
Copy the code
It’s scary. It’s really simple.
When we have two related product lines, ProductA and ProductB, such as screws and nuts, they derive ProductA1, ProductB1 and ProductA2, ProductB2, the former is made by ConcreteFactory1, The latter is made by ConcreteFactory2.
For the Client, all he needs to know is that there is an abstract Factory that can produce both ProductA and ProductB. That is Factory.
The important point is that the abstract Factory delays the construction process to subclass execution through the “Factory method” pattern, that is, the abstract Factory is a pattern based on the Factory method.
So abstract factory, in other words, multiple product lines need to be bound together to form an abstract comprehensive factory, which implements a more “advanced” pattern of “factory approach” in bulk.
conclusion
It’s a little convoluted, but I feel like I’m already level 10. In conclusion, the point I want to make is that these factory models are not separate existences, but progressive ideas.
Builder mode
The builder model is like when you commission an interior designer to decorate your new home
Pictures: http://tse2.mm.bing.net/th?id=OIP.N3hIhcOq32Bh6Ezi6q6kGwHaFj&pid=Api
The official definition of
Separating a complex build from its representation allows the same build process to create different representations.
If the factory model we talked about takes the creation of the product (object) out of the work, this builder model takes the production of the components inside the product out of the work. Scenarios that do this are suitable for object generation processes with complex, regular modules. In other words, the factory pattern is one class (factory) creating another class (product), while the builder is a property (component) construction process of a class (product) itself.
There are also different versions of the builder mode implementation on the web: more complex versions introduce a Director role to act as an overall context and assemble more silly Builders and products. Or abstract a layer of Builder protocol, with different concrete Builder to construct different products. But I think all of this obscures the focus of the model and is not helpful in understanding it, so I choose a minimalist model here.
struct Builder {
var partA: String
var partB: String
}
struct Product {
var partA: String
var partB: String
init(builder: Builder) {
partA = builder.partA
partB = builder.partB
}
}
// Complete the product creation with builder
let b = Builder(partA: "A", partB: "B")
// The product can be completed with only one Builder
let p = Product(builder: b)
Copy the code
We let the Product be generated ourselves, but its components (properties) are all delegated to the Builder, and it only needs a Builder to do its work.
Prototype
The archetypal pattern gives you an endless stream of self-assigned classes.
Pictures: http://thumbs.dreamstime.com/z/cell-division-two-cells-divide-osmosis-background-other-cells-48181492.jpg
The official definition of
Specify what kind of objects to create with prototype instances, and create new objects by copying these prototypes.
The prototype pattern is as simple as implementing a method that returns your own new object. The implementation I’m using here is not the simplest, and this interface is not required.
The prototype pattern implements deep copy.
protocol Prototype {
func clone(a) -> Prototype
}
struct Product: Prototype {
var title: String
func clone(a) -> Prototype {
return Product(title: title)
}
}
let p1 = Product(title: "p1")
let p2 = p1.clone()
(p2 as? Product)? .title// OUTPUT: p1
Copy the code
Singleton Singleton pattern
Singletons are like a company’s IT department; they are unique and accessible to everyone.
Photo: The IT Crowd
The official definition of
Ensure that a class has only one instance and provide a global access point to access it.
Because this second point is often overlooked, overuse can be extremely harmful, you have no way of knowing where the call is coming from, and this goto-like presence can become a maintenance nightmare.
More common applications of singletons are global access points such as databases and network frameworks.
A singleton is a variant of the stereotype pattern, but the stereotype returns a copy at a time.
Simple implementation of Swift:
class Singleton {
static let sharedInstance = Singleton(a)private init() {
// Use private to prevent new}}let s = Singleton.sharedInstance
let s2 = Singleton(a)// ERROR: initializer is inaccessible due to 'private' protection level
Copy the code
Swift complete implementation:
class Singleton {
static var singleton: Singleton? = nil
private init() {}
static func sharedInstance(a) -> Singleton {
if singleton == nil {
singleton = Singleton()}returnsingleton! }}let s = Singleton.sharedInstance()
let s2 = Singleton(a)// ERROR: initializer is inaccessible due to 'private' protection level
Copy the code
Adapter Adapter mode
The adapter is like a power switch plug.
Pictures: http://www.wap135.com/270/timg08/uploaded/i8/TB2452gtpXXXXaLXXXXXXXXXXXX_!!!! 622114048.jpg
The official definition of
Translate the interface of a class into another interface that the customer wants. The adapter pattern makes it possible for classes to work together that would otherwise not work because of interface incompatibilities.
A class can be called an adapter when it transforms another class in a way that allows it to interact with actual needs. An underlying data model, for example, can be presented with different UI adapters for different presentation needs.
protocol Target {
var value: String { get}}struct Adapter: Target {
let adaptee: Adaptee
var value: String {
return "\(adaptee.value)"
}
init(_ adaptee: Adaptee) {
self.adaptee = adaptee
}
}
struct Adaptee {
var value: Int
}
Adapter(Adaptee(value: 1)).value / / "1"
Copy the code
Bridge Bridge mode
The bridge pattern is such a bridge that it stands between the concrete and the abstract. When you call it, you only see the abstract, but when you implement it internally, you “bridge” the concrete.
Pictures: https://refactoring.guru/design-patterns/bridge
The official definition of
Separate the abstract parts from the implementation parts so that they can be changed independently.
Bridge mode is another somewhat convoluted concept after factory mode. In order to avoid confusion, let’s take a look at the final shape of this mode.
First, suppose we encapsulate a “switching capability” interface.
protocolAbility to switch{
func turnOn(_ on: Bool)
}
Copy the code
This interface has only one method, and the implementer needs to provide what the on/off switch triggers.
Then we abstract a class called “device”, which is interesting:
- First he has an implementation
Ability to switch
And assign a value by initialization. - He has a method of implementation which is provided directly
Ability to switch
The implementation of.
classequipment{
letObj: Switching capabilityfunc turnOn(_ on: Bool) {
obj.turnOn(on)
}
init(_Obj: switching capability) {self.obj = obj
}
}
Copy the code
Thus, a bridge pattern is set up. Before we get to that, let’s just look at how it works:
classTelevision: switching ability{
func turnOn(_ on: Bool) {
if on {
// Turn on the TV
} else {
// Turn off the TV}}}classAir conditioning: switching ability{
func turnOn(_ on: Bool) {
if on {
// Turn on the air conditioner
} else {
// Turn off the air conditioner}}}letTV = device (TV ()) tv.turnon (true) // Turn on the TV
letAircon = Equipment (air conditioner ()) Aircon.Turnon (false) // Turn off the air conditioner
Copy the code
As you can see from this code:
- In the abstract
equipment
When applied to a specific business, this pattern takes the form of a composite implementationAbility to switch
Interface, without inheritance. - When finally called, it is unified by
equipment
As an access point instead ofTV
.air conditioner
These concrete classes, the concrete implementation is through compositioninjectiontoequipment
In the.
Once you understand the process, one thing becomes clear:
Isn’t this about composition instead of inheritance?
That’s right, it proxies out code that needs to be changed through the interface, avoiding inheritance.
But where is the bridge mode?
Bridge Pattern – Wikipedia:
The bridge pattern is a design pattern used in software engineering which is meant to “decouple an abstraction from its implementation so that the two can vary independently”. The bridge pattern decouples abstract and concrete, allowing them to vary independently.
Looking for concrete and abstract from the code, we can find:
The key to this bridge is the variables that are combined in the abstract class.
At the end of the day, you’ll see, isn’t that Adapter and Adaptee? Yeah, design mode is actually a soap opera.
The difference is that the adapter’s concern is how to connect two incompatible classes, whereas the bridge pattern concern is decoupling.
Composite mode
The Composite pattern is just like the organizational structure of a company, with Leaf and Composite, who implement the work method of Component. Each level of this tree structure is a fully functional individual.
Pictures: https://realtimeboard.com/static/images/page/examples/detail/organizational-chart.png
The official definition of
Group objects into a tree structure to represent a partial-whole hierarchy. The composite pattern makes the use of single objects and composite objects consistent.
This combination mode is not the “combination” of “combination is better than inheritance”. It refers to a specific scene in a narrow sense, which is a tree-like structure described in the picture.
There are three Settings to understand this pattern:
- Component: A functional Component.
- Leaf: It implements components.
- Composite: It both implements components and contains multiple components.
protocol Component {
func someMethod(a)
}
class Leaf: Component {
func someMethod(a) {
// Leaf}}class Composite: Component {
var components = [Component] ()func someMethod(a) {
// Composite}}let leaf = Leaf(a)let composite = Composite()
composite.components += [leaf]
composite.someMethod()
leaf.someMethod()
Copy the code
The essence of this model is the character of Composite, and in fact Leaf can be seen as a special Compostie. Since it can be both a functional performer and contain other nodes, this feature can be derived from a highly generic tree structure.
Decorator Decorator pattern
It would be nice if the price of coffee was calculated as milk (sugar (coffee (price: 19 yuan))
Pictures: http://cdn.marksdailyapple.com/wordpress/wp-content/themes/Marks-Daily-Apple-Responsive/images/blog2/coffee.jpg
The official definition of
Add some extra responsibilities to an object dynamically. Decorator patterns are more flexible in terms of adding functionality than subclassing.
Here we use the idea of decorator pattern to design this coffee ordering program:
code
protocol Component {
var cost: Int { get}}protocol Decorator: Component {
var component: Component { get }
init(_ component: Component)}struct Coffee: Component {
var cost: Int
}
struct Sugar: Decorator {
var cost: Int {
return component.cost + 1
}
var component: Component
init(_ component: Component) {
self.component = component
}
}
struct Milk: Decorator {
var cost: Int {
return component.cost + 2
}
var component: Component
init(_ component: Component) {
self.component = component
}
}
Milk(Sugar(Coffee(cost: 19))).cost
Copy the code
When your requirements are piecemeal and keep adding “main dish ingredients”, and the ingredients change frequently, this model can effectively address the explosion of permutations and combinations
A key point to understand is to distinguish between the roles of Component and Decorator. The implementer of a simple Component (coffee) is the object to decorate and can no longer decorate others.
This mode does not have a centralized calculator, each decorator participates in the calculation and outputs the current result.
Facade pattern
Appearance patterns are about simplifying.
Pictures: http://www.3dmgame.com/news/201709/3684484.html
The official definition of
To provide a consistent interface for a set of interfaces in a subsystem, the facade defines a high-level interface that makes the subsystem easier to use.
It’s worth mentioning that this word sounds strange.
When we talk about the facade pattern, we often mean wrapping a complex (old) code base with an easy-to-call surface API without changing its internals.
The facade pattern does not use inheritance, but interfaces and composition.
protocol Facade {
func simpleMethod(a)
}
class LegacyCode {
func someMethod1(a){}func someMethod2(a){}}extension LegacyCode: Facade {
func simpleMethod(a) {
someMethod1()
someMethod2()
}
}
class Client {
let f: Facade = LegacyCode()}let c = Client(a)c.f.simpleMethod()
Copy the code
Flyweight share mode
The share mode is like the CPU’s Cache Memory, which increases speed and decreases Memory by hitting the Cache.
Pictures: http://www.computerhope.com/issues/pictures/cpu_cache_die.jpg
The official definition of
Use sharing techniques to effectively support a large number of fine-grained objects.
The share mode is really a caching system. It is clearly a composite pattern, using factory patterns to create instances. This scenario applies when the system has repeated object creation processes. The benefit is memory saving and speed up.
struct TargetObject {
var title: String?
func printTitle(a) {
print(title)
}
}
class Cache {
var targetObjects = [String: TargetObject] ()func lookup(key: String) -> TargetObject {
if targetObjects.index(forKey: key) == nil {
return TargetObject()}returntargetObjects[key]! }}let c = Cache(a)c.targetObjects["Test"] = TargetObject(title: "Test")
c.lookup(key: "123").printTitle() // nil
c.lookup(key: "Test").printTitle() // Test
Copy the code
Proxy mode
The proxy pattern makes one class a de facto interface to another.
Pictures: http://tse2.mm.bing.net/th?id=OIP.igizh16RdxH-Xq9jCR7KLgHaCx&w=300&h=112&c=7&o=5&dpr=2&pid=1.7
The official definition of
Provide a proxy for other objects to control access to that object.
There are two common proxy scenarios:
- Protection Proxy: Calls an underlying class indirectly from a surface class for security reasons.
- Virtual Proxy: Delaying invocation of a high-consumption class with a low-consumption class for performance reasons.
But their implementation is similar:
protocol Subject {
mutating func operation(a)
}
struct SecretObject: Subject {
func operation(a) {
// real implementation}}struct PublicObject: Subject {
private lazy var s = SecretObject(a)mutating func operation(a) {
s.operation()
}
}
var p = PublicObject()
p.operation()
Copy the code
SecretObject can be seen as either a hidden class or an expensive class. The PublicObject proxy enables information hiding and lazy loading.
Chain of responsibility mode
The chain of responsibility model is like withdrawing money, where each denomination participates in the calculation and responsibility transfer.
Pictures: http://www.joezimjs.com/wp-content/uploads/chain_of_responsibility_atm.png
The official definition of
Avoid coupling the request sender with the receiver, make it possible for multiple objects to receive the request, connect the objects into a chain, and pass the request along the chain until an object handles it.
UIKit’s Touch event applies the chain of responsibility mode
The implementation of this pattern is to both implement an interface and compose the interface so that the next performer can be invoked after the execution is complete.
protocol ChainTouchable {
var next: ChainTouchable? { get }
func touch(a)
}
class ViewA: ChainTouchable {
var next: ChainTouchable? = ViewB(a)func touch(a){ next? .touch() } }class ViewB: ChainTouchable {
var next: ChainTouchable? = ViewC(a)func touch(a){ next? .touch() } }class ViewC: ChainTouchable {
var next: ChainTouchable? = nil
func touch(a) {
print("C")}}let a = ViewA()
a.touch() // OUTPUT: C
Copy the code
Command Command mode
Command mode is an instruction system.
Pictures: http://cdn.wikimg.net/strategywiki/images/thumb/e/e3/Light-bot_2-3.jpg/914px-Light-bot_2-3.jpg
The official definition of
Encapsulate a request into an object, allowing you to parameterize customers with different requests.
The command mode has two characteristics:
- Command logic objectification, a command object that can be passed in as an argument from outside or implemented internally.
- Undo is supported, because each command object knows how to undo itself (anti-command), so it can be encapsulated inside the command object.
protocol Command {
var operation: () -> Void { get }
var backup: String { get }
func undo(a)
}
struct ConcreteCommand: Command {
var backup: String
var operation: () -> Void
func undo(a) {
print(backup)
}
}
struct Invoker {
var command: Command
func execute(a) {
command.operation()
}
func undo(a) {
command.undo()
}
}
let printA = ConcreteCommand(backup: "Default A") {
print("A")}let i1 = Invoker(command: printA)
i1.execute() // OUTPUT: A
let printB = ConcreteCommand(backup: "Default B") {
print("B")}let i2 = Invoker(command: printB)
i2.execute() // OUTPUT: B
i2.undo() // OUTPUT: Default B
Copy the code
Interpreter mode
With the interpreter, Skyrim’s Dragon language is no problem.
Pictures: https://staticdelivery.nexusmods.com/mods/110/images/thumbnails/32821-3-1362476170.jpg
The official definition of
Given a language, define its grammatical representation and define an interpreter that uses the identifier to interpret sentences in the language.
We can implement an interpreter that evaluates the text “1 plus 1”.
protocol Expression {
func evaluate(_ context: String) -> Int
}
struct MyAdditionExpression: Expression {
func evaluate(_ context: String) -> Int {
return context.components(separatedBy: "Add")
.flatMap { Int($0)}.reduce(0, +)}}let c = MyAdditionExpression(a)c.evaluate("1 + 1") // OUTPUT: 2
Copy the code
Iterator Indicates the Iterator mode
Iterators are like rotating sushi, ensuring that each dish is displayed.
Pictures: http://www.sohu.com/a/207894434_99978064
The official definition of
Provides a way to access elements of an aggregate object sequentially without exposing the internal representation of the object.
An iterator is a collection element that can be iterated over with hasNext and Next.
It’s like a chain of responsibility, but it’s a chain that can be broken at any time (it’s possible to stop delegating responsibility at a certain point), and it doesn’t emphasize a complete traversal. Iterators are more like a loop over and over again, each loop emphasizing completeness, so they are better suited for collections scenarios.
Another difference is that iterators provide elements, whereas the chain of responsibility does business with each handler.
protocol AbstractIterator {
func hasNext(a) -> Bool
func next(a) -> Int?
}
class ConcreteIterator: AbstractIterator {
private var currentIndex = 0
var elements = [Int] ()func next(a) -> Int? {
guard currentIndex < elements.count else { currentIndex = 0; return nil }
defer { currentIndex += 1 }
return elements[currentIndex]
}
func hasNext(a) -> Bool {
guard currentIndex < elements.count else { currentIndex = 0; return false }
returnelements[currentIndex] ! =nil}}protocol AbstractCollection {
func makeIterator(a) -> AbstractIterator
}
class ConcreteCollection: AbstractCollection {
let iterator = ConcreteIterator(a)func add(_ e: Int) {
iterator.elements.append(e)
}
func makeIterator(a) -> AbstractIterator {
return iterator
}
}
let c = ConcreteCollection(a)c.add(1)
c.add(2)
c.add(3)
let iterator = c.makeIterator()
while iterator.hasNext() {
print(iterator.next() as Any)}Copy the code
Mediator mode
The mediation pattern is a transmitter for sending messages between objects.
Pictures: http://www.quanjing.com/imgbuy/top-959496.html
The official definition of
By encapsulating a set of object interactions with a mediation object, the mediator loosens the coupling of objects without explicitly referring to each other, and can change their interactions independently.
The mediation mode has a good decoupling effect for the system with complex communication relationship
It is similar to the observer pattern, except that the observer is a broadcast that does not care about the receiver, and the mediator is a fixed-point message delivery that intervenes between two (or more) objects.
protocol Receiver {
func receive(message: String)
}
protocol Mediator: class {
func notify(message: String)
func addReceiver(_ receiver: Receiver)
}
class ConcreteMediator: Mediator {
var recipients = [Receiver] ()func notify(message: String) {
recipients.forEach { $0.receive(message: message) }
}
func addReceiver(_ receiver: Receiver) {
recipients.append(receiver)
}
}
protocol Component: Receiver {
var mediator: Mediator? { get}}struct ConcreteComponent: Component {
weak var mediator: Mediator?
var name: String
func receive(message: String) {
print(name, " receive: ", message)
}
}
var mediator = ConcreteMediator(a)let c1 = ConcreteComponent(mediator: mediator, name: "c1")
let c2 = ConcreteComponent(mediator: mediator, name: "c2")
let c3 = ConcreteComponent(mediator: mediator, name: "c3")
mediator.addReceiver(c1)
mediator.addReceiver(c2)
mediator.addReceiver(c3)
//c1 receive: hi
//c2 receive: hi
//c3 receive: hic1.mediator? .notify(message:"hi")
Copy the code
Memento mode
A memo is a game save.
Pictures: http://gearnuke.com/wp-content/uploads/2015/05/witcher3-ps4-savedata-2.jpg
The official definition of
Capture the internal state of an object and store the state outside of the object without breaking encapsulation.
The pattern has two roles, the Memento itself (the type to store) and the Caretaker (Caretaker) that performs the storage operation.
typealias Memento = [String: String] // chatper: level
protocol MementoConvertible {
var memento: Memento { get }
init? (memento:Memento)}class GameState: MementoConvertible {
var memento: Memento {
return [chapter: level]
}
var chapter: String
var level: String
required init? (memento:Memento) {
self.chapter = memento.keys.first ?? ""
self.level = memento.values.first ?? ""
}
init(chapter: String, level: String) {
self.chapter = chapter
self.level = level
}
}
protocol CaretakerConvertible {
static func save(memonto: Memento, for key: String)
static func loadMemonto(for key: String) -> Memento?
}
class Caretaker: CaretakerConvertible {
static func save(memonto: Memento, for key: String) {
let defaults = UserDefaults.standard
defaults.set(memonto, forKey: key)
defaults.synchronize()
}
static func loadMemonto(for key: String) -> Memento? {
let defaults = UserDefaults.standard
return defaults.object(forKey: key) as? Memento}}let g = GameState(chapter: "Prologue", level: "0")
// after a while
g.chapter = "Second"
g.level = "20"
// want a break
Caretaker.save(memonto: g.memento, for: "gamename")
// load game
let gameState = Caretaker.loadMemonto(for: "gamename") // ["Second": "20"]
Copy the code
Observer mode
The observer model is like pre-ordering, paying and waiting for the goods to be received.
Pictures: http://images.pushsquare.com/news/2015/01/what_the_hecks_going_on_with_playstation_store_pre-orders_in_europe/attachment /0/original.jpg
The official definition of
Defines a one-to-many dependency between objects in which all dependent objects are notified and automatically updated when an object’s state changes.
The observer pattern defines one-to-many dependencies between objects so that when an object changes state, all of its dependencies are notified and updated automatically.
The observer pattern applies to scenarios where an observed (data source) notifies multiple observers.
This pattern allows for loose coupling by adding a layer of interfaces that erase the specific types of observers. (Program for interfaces, not implementations)
One of the most important features of the Observer model is that it is a PUSH model, which in many cases is more efficient and real-time than a pull model.
protocol Observable {
var observers: [Observer] { get }
func add(observer: Observer)
func remove(observer: Observer)
func notifyObservers(a)
}
class ConcreteObservable: Observable {
var observers = [Observer] ()func add(observer: Observer) {
observers.append(observer)
}
func remove(observer: Observer) {
if let index = observers.index(where: {$0 === observer }) {
observers.remove(at: index)
}
}
func notifyObservers(a) {
observers.forEach { $0.update() }
}
}
protocol Observer: class {
func update(a)
}
class ConcreteObserverA: Observer {
func update(a) { print("A")}}class ConcreteObserverB: Observer {
func update(a) { print("B")}}//////////////////////////////////
let observable = ConcreteObservable(a)let a = ConcreteObserverA(a)let b = ConcreteObserverB()
observable.add(observer: a)
observable.add(observer: b)
observable.notifyObservers() // output: A B
observable.remove(observer: b)
observable.notifyObservers() // output: A
Copy the code
State mode
The state mode is like Mario’s transformation after eating various mushrooms.
Pictures: http://www.superluigibros.com/images/super_mario_bros_3_power_ups.jpg
The official definition of
Allows an object to change its behavior when its internal state changes, and the object appears to modify its class.
The state pattern is similar to the policy pattern, but it encapsulates different states under each ontology instead of algorithms.
protocol State {
func operation(a)
}
class ConcreteStateA: State {
func operation(a) {
print("A")}}class ConcreteStateB: State {
func operation(a) {
print("B")}}class Context {
var state: State = ConcreteStateA(a)func someMethod(a) {
state.operation()
}
}
let c = Context(a)c.someMethod() // OUTPUT: A
c.state = ConcreteStateB(a)// switch state
c.someMethod() // OUTPUT: B
Copy the code
Strategy Mode
Strategic patterns are like different traffic routes, which can be replaced with each other to reach the end.
Photo: Amap iOS
The official definition of
Define a set of algorithms, encapsulate them one by one, and make them interchangeable.
This pattern mainly addresses the dilemma of a stable inheritance tree when the requirements change. He classifies the changes into different categories and then isolates the changes into an interface/protocol instance, allowing the subclasses to make choices later.
One idea that needs to be changed is that when modeling a class, it can not only be limited to objects, but also can be the encapsulation of behaviors.
It is also theoretically feasible to replace interface with inheritance to realize polymorphic behavior. This pattern has another strength: it is dynamic. In terms of what behavior a subclass chooses, it doesn’t have to be written while writing code; It could be something like a user clicking and switching algorithms.
protocol WeaponBehavior {
func use(a)
}
class SwordBehavior: WeaponBehavior {
func use(a) { print("sword")}}class BowBehavior: WeaponBehavior {
func use(a) { print("bow")}}class Character {
var weapon: WeaponBehavior?
func attack(a){ weapon? .use() } }class Knight: Character {
override init() {
super.init()
weapon = SwordBehavior()}}class Archer: Character {
override init() {
super.init()
weapon = BowBehavior()}}///////////////////////////////////
Knight().attack() // output: sword
Archer().attack() // output: bow
Copy the code
Template Method Indicates the Template Method mode
A template method is an inheritance tree derived from an abstract class.
Pictures: https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=3167143621, & FM 27 & gp = = 0. 3882552175 JPG
The official definition of
Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. The template approach allows subclasses to redefine specific steps of an algorithm without changing the structure of that algorithm.
A template method is a method declaration that exists in an abstract class and is implemented concretely by subclasses. In this way, the method produces a set of derivative effects for different products of the mold.
Implement polymorphism through abstract classes and subclasses.
Unfortunately Swift/Objective-C doesn’t have abstract classes, so use a generic class
class Soldier {
func attack(a) {} // <-- Template Method
private init() {} // <-- avoid creation
}
class Paladin: Soldier {
override func attack(a) {
print("hammer")}}class Archer: Soldier {
override func attack(a) {
print("bow")}}Copy the code
Visitor pattern
The visitor model is like a hotel, they all have access to you, and then you take advantage of the infrastructure.
Pictures: https://marketingland.com/wp-content/ml-loads/2014/08/hotel-bell-customer-service-ss-1920.jpg
The official definition of
The main separation of data structures from data operations.
Known as the most complex design pattern, take a look at the implementation code.
protocol Visitor {
func visit(_ c: ComponentA)
func visit(_ c: ComponentB)
}
struct ConcreteVisitor: Visitor {
func visit(_ c: ComponentA) {
c.featureA()
}
func visit(_ c: ComponentB) {
c.featureB()
}
}
protocol Component {
func accept(_ v: Visitor)
}
struct ComponentA: Component {
func featureA(a) {
print("Feature A")}func accept(_ v: Visitor) {
v.visit(self)}}struct ComponentB: Component {
func featureB(a) {
print("Feature B")}func accept(_ v: Visitor) {
v.visit(self)}}let components: [Component] = [ComponentA(), ComponentB()]
components.forEach {
$0.accept(ConcreteVisitor()}Copy the code
To understand this pattern, you need to understand some concepts:
As you can see from this article, the Visitor pattern in Design Pattern (GoF) is an application of Java to solve Double Dispatch. .
We use Swift to realize the double distribution problem in this paper
protocol Event {}
class BlueEvent: Event {}
class RedEvent: Event {}
class Handler {
func handle(_ e: Event) {
print("Event")}func handle(_ r: RedEvent) {
print("RedEvent")}func handle(_ b: BlueEvent) {
print("BlueEvent")}}let b = BlueEvent(a)let r = RedEvent(a)let c = Handler(a)c.handle(b) // OUTPUT: BlueEvent
c.handle(r) // OUTPUT: RedEvent
Copy the code
Verification found that Swift supports double distribution.
What is Double Dispatch?
To explain this, we need to understand what Dispatch is.
Dispatch or Single Dispatch, Dynamic Dispatch, wiki:
In most object-oriented systems, the concrete function that is called from a function call in the code depends on the dynamic type of a single object and therefore they are known as single dispatch calls, or simply virtual function calls. In the case of polymorphism, at runtime, the virtual method is executed by which implementation, such a binding action is dispatched.
What virtual methods? Take a look at the wiki explanation:
In short, a virtual function defines a target function to be executed, but the target might not be known at compile time. A virtual method is a method whose implementation is not determined at compile time, and we can think of it as a method declared in an interface.
Ok, so we now know that a binding of a virtual method is a dispatch, and a double dispatch is two bindings.
So how does double-distributed code trigger distribution?
- The polymorphism generated by the overload causes a dispatch
- Override overrides the polymorphism implemented by the interface and causes a second dispatch
Understanding this is what this pattern is doing.
Of course, it also has the additional benefit that specific business classes can be dropped into the collection to execute batch Accept visitor.