设计模式-24.访问者模式

244 阅读2分钟

一句话总结

表示一个作用于某对象结构中各元素的操作。可以在不改变各元素类的前提下定义作用于这些元素的新操作。

需求

如下图,男人女人处在不同的状态有不同的反应,那么怎么用面向对象实现呢?

image.png

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)
        }
    }
}

何时使用?

访问者模式适用于数据结构相对稳定的系统,比如人类只分为男人女人,男人女人又可以有很多不同的状态。

优点:访问者模式使增加新的状态很容易。

缺点:访问者模式使数据结构的增加变得困难。比如人类要增加一个中性性别的话,就需要在每个状态类中增加相应的处理逻辑。