一句话总结
表示一个作用于某对象结构中各元素的操作。可以在不改变各元素类的前提下定义作用于这些元素的新操作。
需求
如下图,男人女人处在不同的状态有不同的反应,那么怎么用面向对象实现呢?
Code V1.0
很容易想到用两个类man和woman来实现,但是如果增加状态比如结婚的话,就需要在各自类的getConclusion()方法中增加判断,不符合开放-封闭原则。
static func main() {
var persons: [Person] = []
let man = Man()
man.action = "成功"
persons.append(man)
let woman = Woman()
woman.action = "成功"
persons.append(woman)
let man1 = Man()
man1.action = "失败"
persons.append(man1)
let woman1 = Woman()
woman1.action = "失败"
persons.append(woman1)
let man2 = Man()
man2.action = "恋爱"
persons.append(man2)
let woman2 = Woman()
woman2.action = "恋爱"
persons.append(woman2)
for item in persons {
item.getConclusion()
}
}
protocol Person {
var action: String { set get }
func getConclusion()
}
class Man: Person {
var action: String = ""
func getConclusion() {
if action == "成功" {
print("\(Self.self) \(action)时,背后多半有一个伟大的女人")
} else if action == "失败" {
print("\(Self.self) \(action)时,闷头喝酒谁也不用劝")
} else if action == "恋爱" {
print("\(Self.self) \(action)时,凡事不懂也要装懂")
}
}
}
class Woman: Person {
var action: String = ""
func getConclusion() {
if action == "成功" {
print("\(Self.self) \(action)时,背后大多有一个不成功的男人")
} else if action == "失败" {
print("\(Self.self) \(action)时,眼泪汪汪谁也劝不了")
} else if action == "恋爱" {
print("\(Self.self) \(action)时,懂也装不懂")
}
}
}
Code V2.0
用访问者实现这个需求,需要增加状态-结婚时,只需要增加结婚类就行,无需在其它类中改动。
static func main() {
let o = ObjectStructure()
o.attach(person: Man())
o.attach(person: Woman())
o.display(visitor: Success())
o.display(visitor: Failing())
o.display(visitor: Amativeness())
}
protocol Action {
func getManConclusion(man: Man)
func getWomanConclusion(woman: Woman)
}
protocol Person {
func accept(visitor: Action)
}
class Man: Person {
func accept(visitor: Action) {
visitor.getManConclusion(man: self)
}
}
class Woman: Person {
func accept(visitor: Action) {
visitor.getWomanConclusion(woman: self)
}
}
class Success: Action {
func getManConclusion(man: Man) {
print("\(man.self) \(Self.self)时,背后多半有一个伟大的女人")
}
func getWomanConclusion(woman: Woman) {
print("\(woman.self) \(Self.self)时,背后大多有一个不成功的男人")
}
}
class Failing: Action {
func getManConclusion(man: Man) {
print("\(man.self) \(Self.self)时,闷头喝酒谁也不用劝")
}
func getWomanConclusion(woman: Woman) {
print("\(woman.self) \(Self.self)时,眼泪汪汪谁也劝不了")
}
}
class Amativeness: Action {
func getManConclusion(man: Man) {
print("\(man.self) \(Self.self)时,凡事不懂也要装懂")
}
func getWomanConclusion(woman: Woman) {
print("\(woman.self) \(Self.self)时,懂也装不懂")
}
}
class ObjectStructure {
var persons: [Person] = []
func attach(person: Person) {
persons.append(person)
}
func display(visitor: Action) {
for item in persons {
item.accept(visitor: visitor)
}
}
}
何时使用?
访问者模式适用于数据结构相对稳定的系统,比如人类只分为男人女人,男人女人又可以有很多不同的状态。
优点:访问者模式使增加新的状态很容易。
缺点:访问者模式使数据结构的增加变得困难。比如人类要增加一个中性性别的话,就需要在每个状态类中增加相应的处理逻辑。