using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace DesignPattern
{
internal class VisitorPattern
{
}
//访问者模式:表示一个作用于某对象结构中的各个元素的操作。访问者模式可以让你在不改变各元素的类的前提下定义作用于这些元素的新操作
/// <summary>
/// 员工类:充当抽象元素类
/// </summary>
interface Employee
{
void Accept(Department handler);//接收一个抽象访问者访问
}
/// <summary>
/// 全职员工类:充当具体元素类
/// </summary>
class FulltimeEmployee : Employee
{
private string name; //员工姓名
private double weeklyWage;//员工周薪
private int workTime;//工作时间
public FulltimeEmployee(string name, double weeklyWage, int workTime)
{
this.name = name;
this.weeklyWage = weeklyWage;
this.workTime = workTime;
}
public string Name { get => name; set => name = value; }
public double WeeklyWage { get => weeklyWage; set => weeklyWage = value; }
public int WorkTime { get => workTime; set => workTime = value; }
public void Accept(Department handler)
{
handler.Visit(this);//调用访问者的访问方法
}
}
/// <summary>
/// 兼职员工类:充当具体元素类
/// </summary>
class ParttimeEmployee : Employee
{
private string name; //员工姓名
private double hourWage;//员工周薪
private int workTime;//工作时间
public ParttimeEmployee(string name, double hourWage, int workTime)
{
this.name = name;
this.hourWage = hourWage;
this.workTime = workTime;
}
public string Name { get => name; set => name = value; }
public double HourWage { get => hourWage; set => hourWage = value; }
public int WorkTime { get => workTime; set => workTime = value; }
public void Accept(Department handler)
{
handler.Visit(this);//调用访问者的访问方法
}
}
/// <summary>
/// 部门类:充当抽象访问者类
/// </summary>
abstract class Department
{
//声明一组重载的访问方法,用于访问不同类型的具体元素 //或者用不用的方法名将访问不同类型员工的方法区分开
public abstract void Visit(FulltimeEmployee employee);
public abstract void Visit(ParttimeEmployee employee);
}
/// <summary>
/// 财务部类:充当具体访问者
/// </summary>
class FADeprtment : Department
{
//实现财务部对全职员工的访问 (访问器中会对注入的对象进行各自部门的处理步骤)
public override void Visit(FulltimeEmployee employee)//计算员工的工作时间和实际工资
{
int workTime = employee.WorkTime;
double weekWage = employee.WeeklyWage;
if (workTime > 40)
{
weekWage = weekWage + (workTime - 40) * 100;
}
else if (workTime < 40)
{
weekWage = weekWage - (40 - workTime) * 80;
if (weekWage < 0)
{
weekWage = 0;
}
}
Console.WriteLine("正式员工{0}的实际工资为:{1}元", employee.Name, weekWage);
}
//实现财务部对兼职员工的访问
public override void Visit(ParttimeEmployee employee)//通过重载实现对不同类型员工的访问
{
int workTime = employee.WorkTime;
double hourWage = employee.HourWage;
Console.WriteLine("临时工{0}的实际工资为:{1}元", employee.Name, workTime * hourWage);
}
}
/// <summary>
/// 人力资源部:充当具体访问者类
/// </summary>
class HRDepartment : Department
{
//实现人力部对全职员工的访问
public override void Visit(FulltimeEmployee employee)//通过重载实现对不同类型员工的访问
{
int workTime = employee.WorkTime;
Console.WriteLine("正式员工{0}的实际工作时间为:{1}小时", employee.Name, workTime);
if (workTime > 40)
{
Console.WriteLine("正式员工{0}的加班时间为{1}小时", employee.Name, workTime - 40);
}
else if (workTime < 40)
{
Console.WriteLine("正式员工{0}的请加时间为:{1}小时", employee.Name, 40 - workTime);
}
}
//实现人力部对兼职员工的访问
public override void Visit(ParttimeEmployee employee)
{
int workTime = employee.WorkTime;
Console.WriteLine("临时工{0}的实际工作时间为:{1}小时", employee.Name, workTime);
}
}
/// <summary>
/// 员工列表类:充当对象结构
/// </summary>
class EmployeeList
{
//定义一个集合用于存储员工对象
private ArrayList list = new ArrayList();
public void AddEmployee(Employee employee)
{
list.Add(employee);
}
//遍历访问员工集合中每一个员工对象
public void Accept(Department handler)
{
foreach (object obj in list)
{
((Employee)obj).Accept(handler);
}
}
}
//测试客户端
class program22 {
public void main() {
//在配置文件APP.config中存储具体访问者类的类名
string appSettingString = "DesignPattern.FADeprtment";//模拟从配置文件中取出来的财务部门类
EmployeeList list = new EmployeeList(); //员工列表
Employee fte1, fte2, fte3, pte1, pte2; //员工
fte1 = new FulltimeEmployee("张无忌", 3200, 45);
fte2 = new FulltimeEmployee("杨过", 2000, 40);
fte3 = new FulltimeEmployee("段誉", 2400, 38);
pte1 = new ParttimeEmployee("洪七公", 80, 20);
pte2 = new ParttimeEmployee("郭靖", 80, 20);
Department dep;
//反射生成对象
dep = (Department)Assembly.Load("DesignPattern").CreateInstance(appSettingString);
list.Accept(dep);
//输出结果
//正式员工张无忌的实际工资为:3700元。
//正式员工杨过的实际工资为:2000元。
//正式员工段誉的实际工资为:2240元。
//临时工洪七公的实际工资为:1600元。
//临时工郭靖的实际工资为1080元。
//如果更改具体访问者类,无需修改源代码,只需修改配置文件即可
appSettingString = "DesignPattern.HRDepartment";//模拟从配置文件中取出来的人力部门
//输出结果
//正式员工张无忌的实际工作时间为:45小时。
//正式员工张无忌的加班时间为:5小时。
//正式员工杨过的实际工作时间为:40小时。
//正式员工段誉的实际工作时间为:38小时。
//正式员工段誉的请假时间为:2小时。
//临时工洪七公的实际工作时间为:20小时。
//临时工郭靖的实际工作时间为:18小时。
//如果要在系统中增加一种新的访问模式,无须修改源码,只需要增加一个新的具体访问者类即可,符合开闭原则
//但如果增加一种新的员工为退休员工,由于源系统并未提供相应的访问接口,所以必须对原有系统进行修改,则违背了开闭原则
}
}
}