C# 设计模式(行为型模式):访问者模式
在复杂的系统中,我们可能需要对一组对象执行不同的操作,而这些操作往往会根据对象的类型有所不同。访问者模式(Visitor Pattern)是一种行为型设计模式,它可以帮助我们将数据结构与操作解耦,使得新增操作变得更加灵活。
访问者模式的定义
访问者模式是一种将操作与其作用的对象结构分离的设计模式。它通过为对象结构增加一个访问者(Visitor)对象,将需要对数据结构进行的操作从数据结构本身分离出来。
访问者模式的结构
访问者模式通常由以下几个部分组成:
- Visitor(访问者): 定义对元素进行访问的操作接口。
- ConcreteVisitor(具体访问者): 实现访问者接口,定义对每种具体元素的操作。
- Element(元素): 定义一个接受访问者的方法(Accept),允许访问者访问自身。
- ConcreteElement(具体元素): 实现接受操作,并将自身作为参数传递给访问者。
- ObjectStructure(对象结构): 管理元素的集合,并提供遍历元素的功能。
示例:公司员工的薪资计算
我们以计算不同类型员工的薪资为例:
- 普通员工的薪资按基本工资计算。
- 部门经理的薪资需要额外加上绩效奖金。
代码实现
using System;
using System.Collections.Generic;// 访问者接口
public interface IVisitor
{void Visit(Employee employee);void Visit(Manager manager);
}// 元素接口
public interface IElement
{void Accept(IVisitor visitor);
}// 普通员工类
public class Employee : IElement
{public string Name { get; set; }public double Salary { get; set; } // 基本工资public Employee(string name, double salary){Name = name;Salary = salary;}public void Accept(IVisitor visitor){visitor.Visit(this);}
}// 部门经理类
public class Manager : IElement
{public string Name { get; set; }public double Salary { get; set; } // 基本工资public double Bonus { get; set; } // 绩效奖金public Manager(string name, double salary, double bonus){Name = name;Salary = salary;Bonus = bonus;}public void Accept(IVisitor visitor){visitor.Visit(this);}
}// 具体访问者:薪资计算器
public class SalaryCalculator : IVisitor
{public void Visit(Employee employee){Console.WriteLine($"员工 {employee.Name} 的薪资是:{employee.Salary}");}public void Visit(Manager manager){Console.WriteLine($"经理 {manager.Name} 的薪资是:{manager.Salary + manager.Bonus}");}
}// 对象结构
public class Company
{private List<IElement> _elements = new List<IElement>();public void AddElement(IElement element){_elements.Add(element);}public void ShowSalaries(IVisitor visitor){foreach (var element in _elements){element.Accept(visitor);}}
}// 测试代码
class Program
{static void Main(string[] args){// 创建公司对象结构Company company = new Company();company.AddElement(new Employee("张三", 5000));company.AddElement(new Manager("李四", 8000, 2000));// 创建访问者SalaryCalculator calculator = new SalaryCalculator();// 计算薪资company.ShowSalaries(calculator);}
}
输出结果
员工 张三 的薪资是:5000
经理 李四 的薪资是:10000
访问者模式的优缺点
优点
- 符合单一职责原则: 将数据结构和操作解耦。
- 扩展性好: 增加新的访问者时,无需修改数据结构。
- 灵活性高: 可以在不修改元素类的前提下,为对象结构增加新的操作。
缺点
- 违反开闭原则: 如果需要修改元素类,则需要修改所有相关代码。
- 实现复杂: 对象结构和访问者之间的依赖关系较复杂。
- 双分派问题: 在访问者和元素之间引入了双分派机制,可能导致性能开销。
适用场景
- 对象结构稳定,但需要频繁增加新操作。
- 不同类型的对象需要执行不同的操作,并且这些操作易于变化。
总结
访问者模式将操作从对象结构中分离出来,通过访问者对对象进行扩展和操作,特别适用于对象结构稳定但操作多变的场景。在实际开发中,例如编译器中的抽象语法树遍历、报表生成等场景,都可以考虑使用访问者模式。