【设计模式】访问者模式

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

相关推荐
kkeeper~4 小时前
0基础C语言积跬步之深入理解指针(5下)
c语言·开发语言
一直不明飞行5 小时前
Java的equals(),hashCode()应该在什么时候重写
java·开发语言·jvm
盲敲代码的阿豪5 小时前
Python 入门基础教程(爬虫前置版)
开发语言·爬虫·python
多加点辣也没关系5 小时前
设计模式-解释器模式
设计模式·解释器模式
曹牧5 小时前
C# WinForms应用程序中展示JSON内容
c#
basketball6165 小时前
C++ 构造函数完全指南:从入门到进阶
java·开发语言·c++
互联科技报5 小时前
2026超融合选型:Top5品牌与市场格局解读
开发语言·perl
weixin199701080166 小时前
[特殊字符] 智能数据采集:数字化转型的“数据石油勘探队”(附Python实战源码)
开发语言·python
想唱rap6 小时前
IO多路转接之poll
服务器·开发语言·数据库·c++
@杰克成6 小时前
Java学习30
java·开发语言·学习