下面我們把本章正文部分的HR系統示例進一步復雜化:
1、 系統管理的人員類型包括三大類4小類:
a. 員工(Employee):包括普通員工(General Employee),經理(Manager)
b. 臨時員工(Temporary)
c. 外聘專家(Expert)
2、 管理的內容包括三大類8小類,而且預期還會不斷增加
a. 薪金:包括底薪、司齡工資(與在公司工作年限相關)、不定期的崗位加薪和外聘專家的聘金
b. 保險和公積金:養老保險和住房公積金
c. 假期:年休假、崗位增休假
3、 現有功能需求
a. 薪金:
i. 司齡工資:每年增加50元
ii. 不定期的崗位加薪:計劃給普通員工和經理分別加薪15%和10%
b. 保險和公積金:為了簡化示例,養老保險和住房公積金分別按最後應發收入合計的5%和15%扣除
c. 假期:
i. 年休假:所有員工(普通員工、經理)按照司齡從每年5天起,每滿5年年度增加5天逐級遞增
ii. 崗位增休假:計劃在現有休假基礎上,普通員工每年增加3天,經理每年增加5天
請采用本章介紹的任意一種訪問者模式實現方式(“經典方式”、“Dynamic方式”和“LINQ + 委托方式”),完成上述功能,並通過單元測試驗證。
要求:
1、 依賴關系盡可能簡潔
2、 實現方式盡可能簡潔、實用
3、 便於從“人員類型”和“管理內容”兩方面擴展
分析
1、由於需要同時從管理內容和人員類型兩方面進行調整,所有需要借助.NET平台解耦雙因素依賴關系
2、為了實現簡便采用LINQ + 委托方式
3、為了便於隨著應用項目維護進行修改,將所有人員類型和管理內容以配置方式動態載入
4、為了簡化眾多內容,提供統一的Facade接口,協調眾多人員類型和管理內容間的行為匹配
參考實現
1、人員類型定義
#region Staff
abstract class Person
{
public string Name { get; set; }
public virtual double Income { get; set;}
public virtual object Clone() {return MemberwiseClone();}
}
/// <summary>
/// 外聘專家
/// </summary>
class Expert : Person
{
public Expert(double cost)
{
Cost = cost;
Income = Cost;
}
public double Cost { get; set; }
}
abstract class Employee : Person { }
class GeneralEmployee : Employee
{
public GeneralEmployee(double basicSalary, int workingYears)
{
BasicSalary = basicSalary;
WorkingYears = workingYears;
}
public double BasicSalary { get; set; }
public double ExtraSalary { get; set; }
public int WorkingYears { get; set; }
public int VacationDays { get; set; }
public override double Income{get{return BasicSalary + ExtraSalary;}}
}
class Temporary : Employee
{
public double Wage { get; set; }
public override double Income{get{return Wage;}}
}
class Mananger : GeneralEmployee
{
public Mananger(double basicSalary, int workingYears, string department)
: base(basicSalary, workingYears)
{
Department = department;
}
public string Department { get; private set; }
}
#endregion
2、訪問接口和訪問過程定義
class HrRuntime
{
/// <summary>
/// 所有Element接受Visitor的統一入口
/// </summary>
/// <remarks>
/// Type 表示適用的人員類別
/// Action 表示Visitor擴展的功能
/// </remarks>
public IEnumerable<KeyValuePair<Type, Action<Person>>> Registry { get; set; }
/// <summary>
/// 所有Element
/// </summary>
public List<Person> Staff { get; set; }
/// <summary>
/// 調用各個適用的Visitor
/// </summary>
public void Visit()
{
if(Registry.Count() == 0) return;
if(Staff.Count() == 0) return;
// 動態生成傳統Visit各個接口的過程
// VisitGeneralExpert()
// VisitGeneralTemporary()
// VisitGeneralGeneralEmployee()
// VisitGeneralManager()
var visitorsByType = Registry.GroupBy(x => x.Key);
// 動態執行Visit()過程
Staff.ForEach(x => Registry.Where(a => a.Key == x.GetType()).ToList().ForEach(a => a.Value(x)));
}
public T FindClone<T>(string name)
where T : Person
{
return (T)(Staff.FirstOrDefault(x=>string.Equals(x.Name, name)).Clone());
}
}
3、單元測試驗證各種管理措施與各類人員間的訪問效果
HrRuntime runtime;
const double MaxMistake = 0.1;
[TestInitialize]