A fundamental customer instance
The customer design sample is among the behavioral patterns, it’s used to increase an object with a given performance with out truly modifying it. Sounds cool, proper? Really this sample is what provides SwiftUI superpowers, let me present you the way it works.
open class View {}
ultimate class FirstView: View {}
ultimate class SecondView: View {}
ultimate class ThirdView: View {}
struct HeightVisitor {
func go to(_ view: FirstView) -> Float { 16 }
func go to(_ view: SecondView) -> Float { 32 }
func go to(_ view: ThirdView) -> Float { 64 }
}
protocol AcceptsHeightVisitor {
func settle for(_ customer: HeightVisitor) -> Float
}
extension FirstView: AcceptsHeightVisitor {
func settle for(_ customer: HeightVisitor) -> Float { customer.go to(self) }
}
extension SecondView: AcceptsHeightVisitor {
func settle for(_ customer: HeightVisitor) -> Float { customer.go to(self) }
}
extension ThirdView: AcceptsHeightVisitor {
func settle for(_ customer: HeightVisitor) -> Float { customer.go to(self) }
}
let customer = HeightVisitor()
let view1: AcceptsHeightVisitor = FirstView()
let view2: AcceptsHeightVisitor = SecondView()
let view3: AcceptsHeightVisitor = ThirdView()
print(view1.settle for(customer))
print(view2.settle for(customer))
print(view3.settle for(customer))
First we outline our customized view lessons, this may assist to visualise how the sample works. Subsequent we outline the precise HeightVisitor
object, which can be utilized to calculate the peak for every view kind (FirstView, SecondView, ThirdView). This fashion we do not have to change these views, however we will outline a protocol AcceptsHeightVisitor
, and lengthen our lessons to just accept this customer object and calculate the end result utilizing a self pointer. 👈
On the decision aspect we will provoke a brand new customer occasion and easily outline the views utilizing the protocol kind, this manner it’s doable to name the settle for customer methodology on the views and we will calculate the peak for every kind with out altering the inner construction of those lessons.
A generic customer
We are able to additionally make this sample extra generic by making a Swift protocol with an related kind.
open class View {}
ultimate class FirstView: View {}
ultimate class SecondView: View {}
ultimate class ThirdView: View {}
struct HeightVisitor {
func go to(_ view: FirstView) -> Float { 16 }
func go to(_ view: SecondView) -> Float { 32 }
func go to(_ view: ThirdView) -> Float { 64 }
}
protocol Customer {
associatedtype R
func go to<O>(_ object: O) -> R
}
protocol AcceptsVisitor {
func settle for<V: Customer>(_ customer: V) -> V.R
}
extension AcceptsVisitor {
func settle for<V: Customer>(_ customer: V) -> V.R { customer.go to(self) }
}
extension FirstView: AcceptsVisitor {}
extension SecondView: AcceptsVisitor {}
extension ThirdView: AcceptsVisitor {}
extension HeightVisitor: Customer {
func go to<O>(_ object: O) -> Float {
if let o = object as? FirstView {
return go to(o)
}
if let o = object as? SecondView {
return go to(o)
}
if let o = object as? ThirdView {
return go to(o)
}
fatalError("Go to methodology unimplemented for kind (O.self)")
}
}
let customer = HeightVisitor()
let view1: AcceptsVisitor = FirstView()
let view2: AcceptsVisitor = SecondView()
let view3: AcceptsVisitor = ThirdView()
print(view1.settle for(customer))
print(view2.settle for(customer))
print(view3.settle for(customer))
You should use the generic Customer
protocol to outline the customer and the AcceptsVisitor
protocol to simply lengthen your objects to just accept a generic customer kind. Should you select this strategy you continue to should implement the generic go to methodology on the Customer, forged the article kind and name the sort particular go to methodology. This fashion we moved the go to name logic into the customer. 🙃
Because the views already conforms to the AcceptsVisitor
protocol, we will simply lengthen them with different guests. For instance we will outline a colour customer like this:
struct ColorVisitor: Customer {
func go to(_ view: FirstView) -> String { "purple" }
func go to(_ view: SecondView) -> String { "inexperienced" }
func go to(_ view: ThirdView) -> String { "blue" }
func go to<O>(_ object: O) -> String {
if let o = object as? FirstView {
return go to(o)
}
if let o = object as? SecondView {
return go to(o)
}
if let o = object as? ThirdView {
return go to(o)
}
fatalError("Go to methodology unimplemented for kind (O.self)")
}
}
let customer = ColorVisitor()
let view1: AcceptsVisitor = FirstView()
let view2: AcceptsVisitor = SecondView()
let view3: AcceptsVisitor = ThirdView()
print(view1.settle for(customer))
print(view2.settle for(customer))
print(view3.settle for(customer))
As you may see it is fairly good that we will obtain this sort of dynamic object extension logic by means of guests. If you wish to see a sensible UIKit instance, be happy to try this text. Below the hood SwiftUI closely makes use of the customer sample to realize some magical TupleView & ViewBuilder associated stuff. This sample is so cool, I extremely suggest to study extra about it. 💪