日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

设计模式的征途—16.访问者(Visitor)模式

發布時間:2023/12/20 asp.net 60 豆豆
生活随笔 收集整理的這篇文章主要介紹了 设计模式的征途—16.访问者(Visitor)模式 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在患者就醫時,醫生會根據病情開具處方單,很多醫院都會存在以下這個流程:劃價人員拿到處方單之后根據藥品名稱和數量計算總價,而藥房工作人員根據藥品名稱和數量準備藥品,如下圖所示。

在軟件開發中,有時候也需要處理像處方單這樣的集合對象結構,在該對象結構中存儲了多個不同類型的對象信息,而且對同一對象結構中的元素的操作方式并不唯一,可能需要提供多種不同的處理方式。在設計模式中,有一種模式可以滿足上述要求,其模式動機就是以不同的方式操作復雜對象結構,該模式就是訪問者模式。

訪問者模式(Visitor)學習難度:★★★★☆使用頻率:★☆☆☆☆

一、OA系統員工數據匯總設計

1.1 需求背景

Background:M公司開發部想要為某企業開發一個OA系統,在該OA系統中包含一個員工信息管理子系統,該企業包括正式員工和臨時工,每周HR部門和財務部等部門需要對員工數據進行匯總,匯總數據包括員工工作時間、員工工資等等。該企業的基本制度如下:

(1)正式員工(Full time Employee)每周工作時間為40小時,不同級別、不同部門的員工每周基本工資不同;如果超過40小時,超出部分按照100元/小時作為加班費;如果少于40小時,所缺時間按照請假處理,請假鎖扣工資以80元/小時計算,直到基本工資扣除到0為止。除了記錄實際工作時間外,HR部需要記錄加班時長或請假時長,作為員工平時表現的一項依據。

(2)臨時員工(Part time Employee)每周工作時間不固定,基本工資按照小時計算,不同崗位的臨時工小時工資不同。HR部只需要記錄實際工作時間。

HR人力資源部和財務部工作人員可以根據各自的需要對員工數據進行匯總處理,HR人力資源部負責匯總每周員工工作時間,而財務部負責計算每周員工工資。

1.2 初始設計

  M公司開發人員針對需求,提出了一個初始的解決方案,其核心代碼如下:

public class EmployeeList{// 員工集合private IList<Employee> empList = new List<Employee>();// 增加員工public void AddEmployee(Employee emp){this.empList.Add(emp);}// 處理員工數據public void Handle(string deptName){if (deptName.Equals("財務部")){foreach (var emp in empList){if (emp.GetType().Equals("FullTimeEmployee")){Console.WriteLine("財務部處理全職員工數據!");}else{Console.WriteLine("財務部處理兼職員工數據!");}}}else if (deptName.Equals("人力資源部")){foreach (var emp in empList){if (emp.GetType().Equals("FullTimeEmployee")){Console.WriteLine("人力資源部處理全職員工數據!");}else{Console.WriteLine("人力資源部處理兼職員工數據!");}}}}}

  不難發現,該解決方案存在以下問題:

  (1)EmployeeList類非常龐大,承擔了過多的職責,既不便于代碼復用,也不便于系統擴展,違背了單一職責原則。

  (2)包含了大量的if-else語句,測試和維護的難度增大。

  (3)如果要新增一個部門來操作員工數據集合,那么不得不修改EmployeeList類的源代碼,違背了開閉原則。

  訪問者模式是一個可以考慮用來解決的方案,它可以在一定程度上解決上述問題(大部分問題)。

二、訪問者模式概述

2.1 訪問者模式簡介

  訪問者模式是一種較為復雜的行為型模式,它包含訪問者和被訪問元素兩個主要組成部分,這些被訪問的元素通常具有不同的類型,且不同的訪問者可以對它們進行不同的訪問操作。例如:處方單中的各種藥品信息就是被訪問的元素,而劃價人員和藥房工作人員就是訪問者。訪問者模式可以使得用戶在不修改現有系統的情況下擴展系統的功能,為這些不同類型的元素增加新的操作。

訪問者(Visitor)模式:提供一個作用于某對象結構中的各元素的操作表示,它使得可以在不改變各元素的類的前提下定義作用于這些元素的新操作。訪問者模式是一種對象行為型模式。

2.2 訪問者模式結構

  訪問者模式結構圖中包含以下5個角色:

  (1)Visitor(抽象訪問者):抽象訪問者為對象結構中每一個具體元素類ConcreteElement聲明一個訪問操作,從這個操作的名稱或參數類型可以清楚知道需要訪問的具體元素的類型,具體訪問者則需要實現這些操作方法,定義對這些元素的訪問操作。

  (2)ConcreteVisitor(具體訪問者):具體訪問者實現了抽象訪問者聲明的方法,每一個操作作用于訪問對象結構中一種類型的元素。

  (3)Element(抽象元素):一般是一個抽象類或接口,定義一個Accept方法,該方法通常以一個抽象訪問者作為參數。

  (4)ConcreteElement(具體元素):具體元素實現了Accept方法,在Accept方法中調用訪問者的訪問方法以便完成一個元素的操作。

  (4)ObjectStructure(對象結構):對象結構是一個元素的集合,用于存放元素對象,且提供便利其內部元素的方法。

三、重構OA系統員工數據匯總

3.1 重構后的設計結構

  在上圖中,FinanceDepartment表示財務部,HRDepartment表示人力資源部,它們充當具體訪問者的角色,其抽象父類Department充當抽象訪問者角色;EmployeeList充當對象結構,用于存儲員工列表;FullTimeEmployee表示全職員工,PartTimeEmployee表示兼職員工,它們充當具體元素角色,而其父類IEmployee(這里實現形式是interface)充當抽象元素角色。

3.2 具體代碼實現

  (1)抽象元素=>IEmployee

/// <summary>/// 抽象元素類:Employee/// </summary>public interface IEmployee{void Accept(Department handler);}

  (2)具體元素=>FullTimeEmployee,PartTimeEmployee

/// <summary>/// 具體元素類:FullTimeEmployee/// </summary>public class FullTimeEmployee : IEmployee{public string Name { get; set; }public double WeeklyWage { get; set; }public int WorkTime { get; set; }public FullTimeEmployee(string name, double weeklyWage, int workTime){this.Name = name;this.WeeklyWage = weeklyWage;this.WorkTime = workTime;}public void Accept(Department handler){handler.Visit(this);}}/// <summary>/// 具體元素類:PartTimeEmployee/// </summary>public class PartTimeEmployee : IEmployee{public string Name { get; set; }public double HourWage { get; set; }public int WorkTime { get; set; }public PartTimeEmployee(string name, double hourWage, int workTime){this.Name = name;this.HourWage = hourWage;this.WorkTime = workTime;}public void Accept(Department handler){handler.Visit(this);}}

  (3)對象結構=>EmployeeList

/// <summary>/// 對象結構類:EmployeeList/// </summary>public class EmployeeList{private IList<IEmployee> empList = new List<IEmployee>();public void AddEmployee(IEmployee emp){this.empList.Add(emp);}public void Accept(Department handler){foreach (var emp in empList){emp.Accept(handler);}}

  (4)抽象訪問者=>Department

/// <summary>/// 抽象訪問者類:Department/// </summary>public abstract class Department{// 聲明一組重載的訪問方法,用于訪問不同類型的具體元素public abstract void Visit(FullTimeEmployee employee);public abstract void Visit(PartTimeEmployee employee);}

  (5)具體訪問者=>FinanceDepartment,HRDepartment

/// <summary>/// 具體訪問者類:FinanceDepartment/// </summary>public class FinanceDepartment : Department{// 實現財務部對兼職員工數據的訪問public override void Visit(PartTimeEmployee employee){int workTime = employee.WorkTime;double hourWage = employee.HourWage;Console.WriteLine("臨時工 {0} 實際工資為:{1} 元", employee.Name, workTime * hourWage);}// 實現財務部對全職員工數據的訪問public override void Visit(FullTimeEmployee employee){int workTime = employee.WorkTime;double weekWage = employee.WeeklyWage;if (workTime > 40){weekWage = weekWage + (workTime - 40) * 50;}else if (workTime < 40){weekWage = weekWage - (40 - workTime) * 80;if (weekWage < 0){weekWage = 0;}}Console.WriteLine("正式員工 {0} 實際工資為:{1} 元", employee.Name, weekWage);}}/// <summary>/// 具體訪問者類:HRDepartment/// </summary>public class HRDepartment : Department{// 實現人力資源部對兼職員工數據的訪問public override void Visit(PartTimeEmployee employee){int workTime = employee.WorkTime;Console.WriteLine("臨時工 {0} 實際工作時間為:{1} 小時", employee.Name, workTime);}// 實現人力資源部對全職員工數據的訪問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);}}}

  (6)客戶端調用與測試

public class Program{public static void Main(string[] args){EmployeeList empList = new EmployeeList();IEmployee fteA = new FullTimeEmployee("梁思成", 3200.00, 45);IEmployee fteB = new FullTimeEmployee("徐志摩", 2000, 40);IEmployee fteC = new FullTimeEmployee("梁徽因", 2400, 38);IEmployee fteD = new PartTimeEmployee("方鴻漸", 80, 20);IEmployee fteE = new PartTimeEmployee("唐宛如", 60, 18);empList.AddEmployee(fteA);empList.AddEmployee(fteB);empList.AddEmployee(fteC);empList.AddEmployee(fteD);empList.AddEmployee(fteE);Department dept = AppConfigHelper.GetDeptInstance() as Department;if (dept != null){empList.Accept(dept);}Console.ReadKey();}}

  其中,AppConfigHelper用于從配置文件中獲得具體訪問者實例,配置文件如下:

<?xml version="1.0" encoding="utf-8" ?> <configuration><appSettings><add key="DeptName" value="Manulife.ChengDu.DesignPattern.Visitor.HRDepartment, Manulife.ChengDu.DesignPattern.Visitor" /></appSettings> </configuration>

  AppConfigHelper的具體代碼如下:

public class AppConfigHelper{public static string GetDeptName(){string factoryName = null;try{factoryName = System.Configuration.ConfigurationManager.AppSettings["DeptName"];}catch (Exception ex){Console.WriteLine(ex.Message);}return factoryName;}public static object GetDeptInstance(){string assemblyName = AppConfigHelper.GetDeptName();Type type = Type.GetType(assemblyName);var instance = Activator.CreateInstance(type);return instance;}} View Code

  編譯運行后的結果如下:

  

  如果需要更換具體訪問者類,無須修改源代碼,只需要修改一下配置文件。例如這里將訪問者由人力資源部更改為財務部:

<?xml version="1.0" encoding="utf-8" ?> <configuration><appSettings><add key="DeptName" value="Manulife.ChengDu.DesignPattern.Visitor.FinanceDepartment, Manulife.ChengDu.DesignPattern.Visitor" /></appSettings> </configuration>

?  此時再次運行則會得到以下結果:

  

  可以看出,如果我們要在系統中新增訪問者,那么無需修改源代碼,只需新增一個新的具體訪問者類即可,從這一點看,訪問者模式符合開閉原則。

  但是,如果我們要在系統中新增具體元素,比如新增一個新的員工類型為“退休人員”,由于原系統并未提供相應的訪問接口,因此必須對原有系統進行修改。所以,從新增新的元素來看,訪問者模式違背了開閉原則

  因此,訪問者模式與抽象工廠模式類似,對于開閉原則的支持具有“傾斜”性,可以方便地新增訪問者,但是添加新的元素較為麻煩。

四、訪問者模式總結

4.1 主要優點

  (1)增加新的訪問操作十分方便,不痛不癢 => 符合開閉原則

  (2)將有關元素對象的訪問行為集中到一個訪問者對象中,而不是分散在一個個的元素類中,類的職責更加清晰 =>?符合單一職責原則

4.2 主要缺點

  (1)增加新的元素類很困難,需要在每一個訪問者類中增加相應訪問操作代碼 => 違背了開閉原則

  (2)元素對象有時候必須暴露一些自己的內部操作和狀態,否則無法供訪問者訪問 => 破壞了元素的封裝性

4.3?應用場景

  (1)一個對象結構包含多個類型的對象,希望對這些對象實施一些依賴其具體類型的操作。=> 不同的類型可以有不同的訪問操作

  (2)對象結構中對象對應的類很少改變?很少改變 很少改變(重要的事情說三遍),但經常需要在此對象結構上定義新的操作。

參考資料

  

  劉偉,《設計模式的藝術—軟件開發人員內功修煉之道》

?

作者:周旭龍

出處:http://edisonchou.cnblogs.com

本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接。

轉載于:https://www.cnblogs.com/edisonchou/p/7247990.html

總結

以上是生活随笔為你收集整理的设计模式的征途—16.访问者(Visitor)模式的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 欧美一级欧美三级在线观看 | 日本簧片在线观看 | 欧美视频一二区 | 69人妻精品久久无人专区 | 国产在线三区 | 黑人巨大精品欧美黑寡妇 | 亚洲福利网址 | 色天天色 | 欧美黑人性猛交xxxx | 日本美女一级片 | 一区二区视频在线 | 久久精品国产大片免费观看 | 国产又大又粗又爽的毛片 | 久久看视频 | www欧美在线 | 精品丰满人妻无套内射 | 懂色a v | 国产精品视频一区二区三区在3 | 日日碰狠狠添天天爽 | 国产日产久久高清欧美一区 | 国产成人无码一区二区在线播放 | 成人国产精品入口免费视频 | 国产高清在线视频观看 | 快播日韩 | jizz中国少妇| r级无码视频在线观看 | 日韩人妻无码精品久久久不卡 | 欧美性猛交ⅹxx乱大交 | 久久久久久久久久久久久久av | 五月婷婷激情网 | 美腿丝袜一区二区三区 | 二区三区偷拍浴室洗澡视频 | 日韩一区二区三区四区五区六区 | 黄色的网站免费观看 | 日韩大尺度视频 | 欧美日韩视频免费 | 国产在线观看中文字幕 | 久久视频在线免费观看 | 欧美一区三区三区高中清蜜桃 | 春色av| 99久久香蕉 | 国产亚洲精品成人av久久ww | 国产资源免费 | 国产三级91 | 免费av网站在线播放 | 国产绳艺sm调教室论坛 | 国产鲁鲁 | av不卡一区二区 | 福利在线播放 | 国产精品亚洲无码 | 国产精品无码久久久久 | 欧洲一级黄色片 | 日韩精品在线观看免费 | 欧美久久久久久久久久久久久久 | 麻豆国产一区二区三区四区 | 国产一区二区三区视频在线播放 | a级黄色录像 | 日本四级电影 | 欧美极品在线观看 | 亚洲美女免费视频 | 一本色道久久综合 | 91日韩精品 | 中文字幕视频在线 | 动漫同人高h啪啪爽文 | 女女高潮h冰块play失禁百合 | 国产一级生活片 | 国产探花视频在线观看 | 日日躁夜夜躁狠狠久久av | 色综合久久88 | 国产成人精 | 精品不卡在线 | 反差在线观看免费版全集完整版 | 免费在线观看黄色网址 | 美女脱光衣服让男人捅 | 天堂va在线 | 成年人免费看 | 亚洲AV无码精品自拍 | 图片区 小说区 区 亚洲五月 | 婷婷国产成人精品视频 | 久久久久爱 | 午夜色大片 | 久久精品亚洲精品国产欧美 | 69xav| 国产精品欧美久久久久天天影视 | 黑人欧美一区二区三区 | 日本丰满少妇一区二区三区 | 中文字幕网址在线 | 夜夜操操操 | 中文久久字幕 | 久久久久久久久福利 | 日本公与丰满熄 | 一级成人黄色片 | 香蕉视频污在线观看 | 日韩av一区二区三区四区 | 欧美男人亚洲天堂 | 中国黄色a级片 | 成人精品免费看 | 春日野结衣av | 波多野结衣免费在线视频 |