【设计模式】访问者模式

访问者模式(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、拼写检查、统计信息;

相关推荐
hggngx548h12 分钟前
有哪些C++20特性可以在Dev-C++中使用?
开发语言·c++·c++20
yue0081 小时前
C# 生成指定位数的编号
开发语言·c#
大笨象、小笨熊1 小时前
Qt Widgets和Qt Quick在开发工控触摸程序的选择
开发语言·qt
红黑色的圣西罗1 小时前
C# List.Sort方法总结
开发语言·c#
E_ICEBLUE2 小时前
Python 教程:如何快速在 PDF 中添加水印(文字、图片)
开发语言·python·pdf
南方的狮子先生2 小时前
【C++】C++文件读写
java·开发语言·数据结构·c++·算法·1024程序员节
Alex艾力的IT数字空间2 小时前
完整事务性能瓶颈分析案例:支付系统事务雪崩优化
开发语言·数据结构·数据库·分布式·算法·中间件·php
mjhcsp2 小时前
C++ 数组:基础与进阶全解析
开发语言·c++
5335ld3 小时前
后端给的post 方法但是要求传表单数据格式(没有{})
开发语言·前端·javascript·vue.js·ecmascript