【设计模式】访问者模式

访问者模式(Visitor Pattern)

概念:

· 一种行为型设计模式;

· 将作用于某些对象结构中的操作封装成独立的访问者类,从而实现在不改变元素类的情况下,对元素进行新的操作;

UML结构:

复制代码
          +----------------+
          |    IVisitor    |   ← 访问者接口
          +----------------+
          | visit(ElementA)|
          | visit(ElementB)|
          +----------------+
                 ^
                 |
        +--------------------+
        | ConcreteVisitor    |   ← 具体访问者,实现具体操作
        +--------------------+
        | visit(ElementA)    |
        | visit(ElementB)    |
        +--------------------+

          +----------------+
          |   IElement     |   ← 元素接口
          +----------------+
          | accept(visitor)|
          +----------------+
                 ^
                 |
        +--------------------+
        | ConcreteElementA   |   ← 具体元素
        +--------------------+
        | operationA()       |
        | accept(visitor)    |
        +--------------------+
        
        +--------------------+
        | ConcreteElementB   |
        +--------------------+
        | operationB()       |
        | accept(visitor)    |
        +--------------------+

代码示例:

cs 复制代码
/// <summary>
/// 产品接口类
/// </summary>
public interface IProduct
{
    void Accept(IVisitor visitor);
}

/// <summary>
/// 访问者接口类
/// </summary>
public interface IVisitor
{
    void Visit(Electronics electronics);
    void Visit(Book book);
    void Visit(Food food);
}

/// <summary>
/// 产品基类
/// </summary>
public abstract class ProductBase
{
    public float _TaxRate { get; set; }
    public float _Price { get; set; }
    public string _Description { get; set; }
    public float _Discount { get; set; }

    public ProductBase(float taxRate, float price, string description, float discount)
    {
        _TaxRate = taxRate;
        _Price = price;
        _Description = description;
        _Discount = discount;
    }

    public abstract void Accept(IVisitor visitor);
}

/// <summary>
/// 具体产品1
/// </summary>
public class Electronics : ProductBase, IProduct
{
    public Electronics(float taxRate, float price, string description, float discount) : base(taxRate, price, description, discount) { }

    public override void Accept(IVisitor visitor)
    {
        visitor.Visit(this);
    }
}

/// <summary>
/// 具体产品2
/// </summary>
public class Book : ProductBase, IProduct
{
    public Book(float taxRate, float price, string description, float discount) : base(taxRate, price, description, discount) { }

    public override void Accept(IVisitor visitor)
    {
        visitor.Visit(this);
    }
}

/// <summary>
/// 具体产品3
/// </summary>
public class Food : ProductBase, IProduct
{
    public Food(float taxRate, float price, string description, float discount) : base(taxRate, price, description, discount) { }

    public override void Accept(IVisitor visitor)
    {
        visitor.Visit(this);
    }
}

/// <summary>
/// 具体访问者1
/// </summary>
public class CalculatePrice : IVisitor
{
    public float TotalPrice { get; set; } = 0;

    public void Visit(Electronics electronics)
    {
        TotalPrice += electronics.Price * (1 + electronics.TaxRate);
        Console.WriteLine($"当前总价格为:{TotalPrice}");
    }

    public void Visit(Book book)
    {
        TotalPrice += book.Price * (1 + book.TaxRate);
        Console.WriteLine($"当前总价格为:{TotalPrice}");
    }

    public void Visit(Food food)
    {
        TotalPrice += food.Price * (1 + food.TaxRate);
        Console.WriteLine($"当前总价格为:{TotalPrice}");
    }
}

/// <summary>
/// 具体访问者2
/// </summary>
public class GenerateDescription : IVisitor
{
    public void Visit(Electronics electronics)
    {
        Console.WriteLine($"电子产品描述:{electronics._Description}");
    }

    public void Visit(Book book)
    {
        Console.WriteLine($"书籍描述:{book._Description}");
    }

    public void Visit(Food food)
    {
        Console.WriteLine($"食物描述:{food._Description}");
    }
}

/// <summary>
/// 具体访问者3
/// </summary>
public class ApplyDiscount : IVisitor
{
    public void Visit(Electronics electronics)
    {
        Console.WriteLine($"电子产品打折规则:{electronics._Discount}");
    }

    public void Visit(Book book)
    {
        Console.WriteLine($"书籍打折规则:{book._Discount}");
    }

    public void Visit(Food food)
    {
        Console.WriteLine($"食物打折规则:{food._Discount}");
    }
}

public class Client
{
    public static void Main()
    {
        ProductBase electronics = new Electronics(0.15f, 5000f, "Gaming Laptop", 0.1f);
        ProductBase book = new Book(0.05f, 80f, "Design Patterns", 0.2f);
        ProductBase food = new Food(0.1f, 20f, "Organic Apple", 0.05f);

        IVisitor calculatePrice = new CalculatePrice();
        IVisitor generateDescription = new GenerateDescription();
        IVisitor applyDiscount = new ApplyDiscount();

        electronics.Accept(calculatePrice);
        electronics.Accept(generateDescription);
        electronics.Accept(applyDiscount);

        book.Accept(calculatePrice);
        book.Accept(generateDescription);
        book.Accept(applyDiscount);

        food.Accept(calculatePrice);
        food.Accept(generateDescription);
        food.Accept(applyDiscount);
    }
}

特点:
优点:

· 符合单一职责原则;

· 易于扩展新的操作;

· 结构清晰:把元素和操作分离,逻辑职责明确;
缺点:

· 扩展新的元素时,需要修改已有的访问者接口和已有的访问者类;

· 违反封装:访问者需要访问元素的内部数据,破坏了封装性;

· 增加系统的复杂度:将操作与元素拆分会导致类的增多;

适用场景:

· 对象结构稳定,元素个数相对固定,但是需要不断增加新操作;

· 对象结构中有很多不同类型的对象,并希望对这些对象实现不同的操作;

· 希望能把数据与操作逻辑分离;

· 希望通过向不同的对象传入相同的参数以实现与其对应的不同操作;

举例场景:

· 文档处理系统

元素:段落、图片、表格;

操作(访问者):导出HTML、拼写检查、统计信息;

相关推荐
C^h5 小时前
c++ string
开发语言·c++
raindayinrain6 小时前
c++高性能--原子操作,无锁编程,操作顺序
开发语言·c++·性能优化
学逆向的6 小时前
C++ 合并命名空间
开发语言·c++·网络安全
Zhao-Jichao6 小时前
VS2026 打包 C++ 程序生成 EXE,借助 Installer Project 扩展工具
开发语言·c++
学逆向的7 小时前
C 局部静态变量
c语言·开发语言·网络安全
大都督会赢的7 小时前
C++第一节课
开发语言·c++
“AI国潮设计-小江”7 小时前
【AIGC实战】Python+Stable Diffusion打造“英歌舞财神”IP,解锁“马到成功”等爆款情绪营销文案设计
开发语言·人工智能·python·prompt·aigc
小王C语言7 小时前
Qt常用控件:容器类控件,标题分组框、标签页(浏览器标签)
开发语言·qt
我是唐青枫8 小时前
Kotlin Delegation 委托详解
开发语言·kotlin
qq_406981038 小时前
共享变量一 关于extern与const
开发语言·c++