目录
访问者模式(Visitor Pattern)
访问者模式(Visitor Pattern)将算法从对象结构中分离出来,从而使算法可以独立于对象而变化。允许在不修改现有代码的情况下向现有对象结构添加新的行为。该模式建立在两个核心组件上:访问者和元素。访问者是一个能够访问所有元素的对象,而元素则是需要接受访问者的对象。在这种模式下,访问者可以在不改变元素本身的情况下对其进行操作。访问者模式的核心思想是,通过让访问者持有某个具体元素的引用,让元素的接受访问者方法中执行具体访问者的操作。
访问者模式的核心角色:
- 抽象访问者(Abstract Visitor):定义了对每个具体元素类的访问操作接口,它的方法签名决定了可以访问哪些元素以及如何访问它们。
- 具体访问者(Concrete Visitor):实现了抽象访问者定义的访问操作接口,具体决定了对元素的实际访问行为。
- 抽象元素(Abstract Element):定义了接受访问者的接口,声明了接受访问者的方法。
- 具体元素(Concrete Element):实现了抽象元素定义的接受访问者的方法,通过调用访问者的具体访问方法来完成具体操作。
- 对象结构(Object Structure):通常由多个具体元素组成的集合,提供了遍历元素集合的方法,用于让访问者访问元素。
优缺点
(1)优点:
- 符合单一职责原则。
- 优秀的扩展性。
- 灵活性。
(2)缺点:
- 具体元素对访问者公布细节,违反了迪米特原则。
- 具体元素变更比较困难。
- 违反了依赖倒置原则,依赖了具体类,没有依赖抽象。
使用场景
- 对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作。
- 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,也不希望在增加新操作时修改这些类。
代码实现
package main
import "fmt"
// 电商平台,需要对用户的购物车中的商品进行不同的操作,例如计算商品总价、打印商品清单等。
// 商品的类型包括书籍(Book)和电子产品(ElectronicProduct)。
// 抽象访问者接口(Visitor):
type Visitor interface {
VisitBook(book *Book)
VisitElectronicProduct(product *ElectronicProduct)
}
// 抽象元素接口(Element)
type Element interface {
Accept(visitor Visitor)
}
// 具体访问者(Concrete Visitor):
type ShoppingCartVisitor struct {
TotalPrice float64
}
func (v *ShoppingCartVisitor) VisitBook(book *Book) {
v.TotalPrice += book.Price
}
func (v *ShoppingCartVisitor) VisitElectronicProduct(product *ElectronicProduct) {
v.TotalPrice += product.Price
}
// 具体元素(Concrete Element):book
type Book struct {
Name string
Price float64
}
func (b *Book) Accept(visitor Visitor) {
visitor.VisitBook(b)
}
// 具体元素(Concrete Element):ElectronicProduct
type ElectronicProduct struct {
Name string
Price float64
}
func (p *ElectronicProduct) Accept(visitor Visitor) {
visitor.VisitElectronicProduct(p)
}
// 对象结构(Object Structure)和具体元素的访问方法
type ShoppingCart struct {
Items []Element
}
func (cart *ShoppingCart) AddItem(item Element) {
cart.Items = append(cart.Items, item)
}
func (cart *ShoppingCart) CalculateTotalPrice(visitor Visitor) float64 {
for _, item := range cart.Items {
item.Accept(visitor)
}
return visitor.(*ShoppingCartVisitor).TotalPrice
}
func main() {
cart := &ShoppingCart{}
book := &Book{Name: "Design Patterns", Price: 49.99}
electronicProduct := &ElectronicProduct{Name: "Smartphone", Price: 599.99}
cart.AddItem(book)
cart.AddItem(electronicProduct)
visitor := &ShoppingCartVisitor{}
totalPrice := cart.CalculateTotalPrice(visitor)
fmt.Printf("Total price: $%.2f\n", totalPrice)
}