【设计模式】访问者模式

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

相关推荐
赵杰伦cpp1 天前
C++的继承机制精讲
java·开发语言·c++·后端
百花~1 天前
JVM(Java虚拟机)~
java·开发语言·jvm
沐苏瑶1 天前
PHP反序列化漏洞
java·开发语言
Chloe_lll1 天前
threejs(七)PBR材质
开发语言·javascript·材质
zh_xuan1 天前
c++ stringstream字符串流的用法
开发语言·c++
小王不爱笑1321 天前
Java 核心知识点查漏补缺(二)
java·开发语言
Lacrimosa&L1 天前
OS_2 进程与线程(进程管理)
java·开发语言
zzywxc7871 天前
解锁 Rust 开发新可能:从系统内核到 Web 前端的全栈革命
开发语言·前端·python·单片机·嵌入式硬件·rust·scikit-learn
大雨淅淅1 天前
【编程语言】Rust 入门
开发语言·后端·rust
桃花键神1 天前
【送书福利-第四十四期】《 深入Rust标准库》
开发语言·后端·rust