前兩篇總結了建立類型的設計模式和結構類型的設計模式。這是模式總結的最後一篇,即行爲類型的模式,它主要是關於類及對象的交互相關的。html
行爲類型的設計模式目錄算法
1.責任鏈模式(爲解除請求的發送者和接收者之間耦合,而使多個對象都有機會處理這個請求。將這些對象連成一條鏈,並沿着這條鏈傳遞該請求,直到有一個對象處理它。)設計模式
目前MVC6中的host中間件就是基於這個模式處理的。但比咱們下面的例子要複雜,能夠參考下它的代碼。
責任鏈的概念能夠考慮下公司內部的請購或者請假流程。好比一個請假流程的請求,中間可能請1天由你的部門主管對象處理,也可能大於3天由你的部門經理對象處理,這個模式其實就是組成了一個流程鏈,對流程請求進行處理。
下邊實現一個請款流程來演示責任鏈模式數據結構
/// <summary> /// 請款請求實體對象 /// </summary> class Loan { public double Amount { get; set; } public string Purpose { get; set; } public int Number { get; set; } } //定義事件參數,保留請求的主題內容 public class LoanEventArgs : EventArgs { internal Loan Loan { get; set; } } /// <summary> /// 爲處理請求對象定義基類 /// </summary> abstract class Approver { // 請款事件 public EventHandler<LoanEventArgs> Loan; // 請款動做,給事件執行 public abstract void LoanHandler(object sender, LoanEventArgs e); // 構造函數,初始化時將動做綁定到事件 public Approver() { Loan += LoanHandler; } //觸發事件 public void ProcessRequest(Loan loan) { OnLoan(new LoanEventArgs { Loan = loan }); } // 執行請款事件請求 public virtual void OnLoan(LoanEventArgs e) { if (Loan != null) { Loan(this, e); } } // 設置或者獲取下一個處理者 public Approver Successor { get; set; } } /// <summary> /// 財務 /// </summary> class Clerk : Approver { public override void LoanHandler(object sender, LoanEventArgs e) { //個人責任範圍我處理 if (e.Loan.Amount < 25000.0) { Console.WriteLine("{0} 批准# {1}", this.GetType().Name, e.Loan.Number); } //不是就給下一個處理吧 else if (Successor != null) { Successor.LoanHandler(this, e); } } } /// <summary> /// 經理 /// </summary> class AssistantManager : Approver { public override void LoanHandler(object sender, LoanEventArgs e) { if (e.Loan.Amount < 45000.0) { Console.WriteLine("{0} 批准# {1}", this.GetType().Name, e.Loan.Number); } else if (Successor != null) { Successor.LoanHandler(this, e); } } } /// <summary> /// 總經理 /// </summary> class Manager : Approver { public override void LoanHandler(object sender, LoanEventArgs e) { if (e.Loan.Amount < 100000.0) { Console.WriteLine("{0} 批准# {1}", sender.GetType().Name, e.Loan.Number); } else if (Successor != null) { Successor.LoanHandler(this, e); } else { Console.WriteLine( "請求# {0} 得開個會研究了!", e.Loan.Number); } } } /// <summary> /// 客戶端調用 /// </summary> class Program { static void Main(string[] args) { // 處理者對象 Approver rohit = new Clerk(); Approver rahul = new AssistantManager(); Approver manoj = new Manager(); //定義下一個處理者責任鏈 rohit.Successor = rahul; rahul.Successor = manoj; // 請求1 var loan = new Loan { Number = 2034, Amount = 24000.00, Purpose = "小金額" }; rohit.ProcessRequest(loan); // 請求2 loan = new Loan { Number = 2035, Amount = 42000.10, Purpose = "通常金額" }; rohit.ProcessRequest(loan); // 請求3 loan = new Loan { Number = 2036, Amount = 156200.00, Purpose = "大金額" }; rohit.ProcessRequest(loan); Console.ReadKey(); } }
二、命令模式(將一個請求封裝爲一個對象,從而使你可用不一樣的請求參數化;對請求排隊或記錄請求日誌,以及支持可取消的操做。)
命令模式由於解耦了請求和執行之間的關係,因此中間封裝了一層命令對象,在封裝的具體命令實現類中能夠實現諸如排隊、撤銷執行和做爲回掉函數使用等框架
public class Light { public void TurnOn() { Console.WriteLine("開燈"); } public void TurnOff() { Console.WriteLine("關燈"); } } /// <summary> /// 命令角色接口 /// </summary> public interface ICommand { void Execute(); } /// <summary> /// 具體命令實現類,負責開燈。 /// </summary> public class FlipUpCommand : ICommand { private Light _light; public FlipUpCommand(Light light) { _light = light; } public void Execute() { _light.TurnOn(); } } /// <summary> /// 具體命令實現 負責關燈 /// </summary> public class FlipDownCommand : ICommand { private Light _light; public FlipDownCommand(Light light) { _light = light; } public void Execute() { _light.TurnOff(); } } /// <summary> /// 命令請求角色,調用執行命令 /// </summary> public class Switch { private List<ICommand> _commands = new List<ICommand>(); public void StoreAndExecute(ICommand command) { _commands.Add(command); command.Execute(); } } /// <summary> /// 客戶端調用 /// </summary> class Program { static void Main(string[] args) { Console.WriteLine("輸入命令 (ON/OFF) : "); string cmd = Console.ReadLine(); Light lamp = new Light();//命令接收 //下邊就是精華,就是將命令的請求和執行分開,弱化請求和執行的耦合關係 ICommand switchUp = new FlipUpCommand(lamp);//封裝具體指令 ICommand switchDown = new FlipDownCommand(lamp);//封裝具體指令 Switch s = new Switch();//命令請求執行 if (cmd == "ON") { s.StoreAndExecute(switchUp); } else if (cmd == "OFF") { s.StoreAndExecute(switchDown); } else { Console.WriteLine("命令 \"ON\" or \"OFF\" 必須發出."); } Console.ReadKey(); } }
三、迭代器模式(提供一種方法順序訪問一個聚合對象中各個元素, 而又不需暴露該對象的內部表示。)ide
迭代器模式是專門針對集合類相似的聚合對象的。見示例函數
/// <summary> /// 迭代器接口 /// </summary> interface IIterator { string FirstItem { get; } string NextItem { get; } string CurrentItem { get; } bool IsDone { get; } } /// <summary> /// 聚合類接口 /// </summary> interface IAggregate { IIterator GetIterator(); //建立索引 string this[int itemIndex] { set; get; } int Count { get; } } /// <summary> /// 聚合類實現 /// </summary> class MyAggregate : IAggregate { List<string> values_ = null; public MyAggregate() { values_ = new List<string>(); } #region IAggregate Members public IIterator GetIterator() { //返回一下實現的迭代器實例,把聚合類自己傳遞給迭代器 return new MyIterator(this); } #endregion public string this[int itemIndex] { get { if (itemIndex < values_.Count) { return values_[itemIndex]; } else { return string.Empty; } } set { values_.Add(value); } } public int Count { get { return values_.Count; } } } /// <summary> /// 迭代器實現 /// </summary> class MyIterator : IIterator { IAggregate aggregate_ = null; int currentIndex_ = 0; public MyIterator(IAggregate aggregate) { aggregate_ = aggregate; } #region IIterator Members public string FirstItem { get { currentIndex_ = 0; return aggregate_[currentIndex_]; } } public string NextItem { get { currentIndex_ += 1; if (IsDone == false) { return aggregate_[currentIndex_]; } else { return string.Empty; } } } public string CurrentItem { get { return aggregate_[currentIndex_]; } } public bool IsDone { get { if (currentIndex_ < aggregate_.Count) { return false; } return true; } } #endregion } class Program { static void Main(string[] args) { MyAggregate aggr = new MyAggregate(); aggr[0] = "1"; aggr[1] = "2"; aggr[2] = "3"; aggr[3] = "4"; aggr[4] = "5"; aggr[5] = "6"; aggr[6] = "7"; aggr[7] = "8"; aggr[8] = "9"; aggr[9] = "10"; IIterator iter = aggr.GetIterator(); for (string s = iter.FirstItem; iter.IsDone == false; s = iter.NextItem) { Console.WriteLine(s); } Console.ReadKey(); } }
四、中介者模式(包裝了一系列對象相互做用的方式,使得這些對象沒必要相互明顯做用,從而使它們能夠鬆散偶合。當某些對象之間的做用發生改變時,不會當即影響其餘的一些對象之間的做用,保證這些做用能夠彼此獨立的變化。)ui
其實中介者模式就是對兩個相互做用的對象中間增長一箇中間處理環節對象來協調二者之間的做用關係。例如如下例子使用同事間發送消息爲例this
//參與者基類 public interface IColleague<t> { //發送信息 void SendMessage(IMediator<t> mediator, T message); //接收信息 void ReceiveMessage(T message); } //參與者具體淚 public class ConcreteColleague<t> : IColleague<t> { private string name; public ConcreteColleague(string name) { this.name = name; } void IColleague<t>.SendMessage(IMediator<t> mediator, T message) { mediator.DistributeMessage(this, message); } void IColleague<t>.ReceiveMessage(T message) { Console.WriteLine(this.name + " received " + message.ToString()); } } //中介者基類 public interface IMediator<t> { //參與者列表 List<icolleague><t>> ColleagueList { get; } //分發信息 void DistributeMessage(IColleague<t> sender, T message); //註冊加入參與人 void Register(IColleague<t> colleague); } //中介者具體實現類 public class ConcreteMediator<t> : IMediator<t> { private List<icolleague><t>> colleagueList = new List<icolleague><t>>(); List<icolleague><t>> IMediator<t>.ColleagueList { get { return colleagueList; } } void IMediator<t>.Register(IColleague<t> colleague) { colleagueList.Add(colleague); } void IMediator<t>.DistributeMessage(IColleague<t> sender, T message) { foreach (IColleague<t> c in colleagueList) if (c != sender) //發送者不接收信息 c.ReceiveMessage(message); } } //客戶端調用 class Program { static void Main(string[] args) { //參與同事列表 IColleague<string> colleagueA = new ConcreteColleague<string>("ColleagueA"); IColleague<string> colleagueB = new ConcreteColleague<string>("ColleagueB"); IColleague<string> colleagueC = new ConcreteColleague<string>("ColleagueC"); IColleague<string> colleagueD = new ConcreteColleague<string>("ColleagueD"); //第一個傳遞消息中介 IMediator<string> mediator1 = new ConcreteMediator<string>(); //註冊參與者到中介 mediator1.Register(colleagueA); mediator1.Register(colleagueB); mediator1.Register(colleagueC); //參與者A發出一條信息 colleagueA.SendMessage(mediator1, "來自A的信息"); //第二個中介者 IMediator<string> mediator2 = new ConcreteMediator<string>(); //將參與者註冊到中介者中 mediator2.Register(colleagueB); mediator2.Register(colleagueD); //參與者B發出一條信息 colleagueB.SendMessage(mediator2, "b中介發出一條信息"); } }
五、備忘錄模式(備忘錄對象是一個用來存儲另一個對象內部狀態的快照的對象。備忘錄模式的用意是在不破壞封裝的條件下,將一個對象的狀態捉住,並外部化,存儲起來,從而能夠在未來合適的時候把這個對象還原到存儲起來的狀態。適合回滾操做)spa
//備忘錄實體對象,存儲發起人對象的狀態 public class Memento<T> { private T state; public T GetState() { return state; } public void SetState(T state) { this.state = state; } } //發起人對象, public class Originator<T> { private T state; //建立備忘錄並保存狀態進去 public Memento<T> CreateMemento() { Memento<T> m = new Memento<T>(); m.SetState(state); return m; } //從備忘錄中恢復對象 public void SetMemento(Memento<T> m) { state = m.GetState(); } //保存狀態到發起人 public void SetState(T state) { this.state = state; } //show public void ShowState() { Console.WriteLine(state.ToString()); } } //備忘錄管理者 public static class Caretaker<T> { //狀態列表 private static List<Memento<T>> mementoList = new List<Memento<T>>(); //保存發起人建立的備忘錄 public static void SaveState(Originator<T> orig) { mementoList.Add(orig.CreateMemento()); } //恢復備忘錄給發起人 public static void RestoreState(Originator<T> orig, int stateNumber) { orig.SetMemento(mementoList[stateNumber]); } } class Program { static void Main(string[] args) { //建立發起人 Originator<string> orig = new Originator<string>(); orig.SetState("state0"); Caretaker<string>.SaveState(orig); //管理者保存發起人的備忘錄 orig.ShowState(); orig.SetState("state1"); Caretaker<string>.SaveState(orig); orig.ShowState(); orig.SetState("state2"); Caretaker<string>.SaveState(orig); orig.ShowState(); //管理者恢復狀態給發起人 Caretaker<string>.RestoreState(orig, 0); orig.ShowState(); // state0 } }
六、觀察者模式(在對象間定義一個一對多的聯繫性,由此當一個對象改變了狀態,全部其餘相關的對象會被通知而且自動刷新。)
這個模式有點相似中介者模式,可是不能混淆了,中介者模式是多對多關係的,觀察者模式是一對多關係,理解了這個關係,就不難理解觀察者模式。
/// <summary> /// 主體基類 (一個倉庫庫存變化通知的例子) /// </summary> interface ISubject { void Subscribe(Observer observer); void Unsubscribe(Observer observer); void Notify(); } /// <summary> /// 主體實現類 /// </summary> public class Subject : ISubject { private List<Observer> observers = new List<Observer>(); private int _int; public int Inventory { get { return _int; } set { // 確保庫存數量有變化,由主體通知給觀察者 if (value > _int) Notify(); _int = value; } } public void Subscribe(Observer observer) { observers.Add(observer); } public void Unsubscribe(Observer observer) { observers.Remove(observer); } public void Notify() { observers.ForEach(x => x.Update()); } } /// <summary> /// 觀察者基類 /// </summary> interface IObserver { void Update(); } /// <summary> /// 觀察者具體實現類 /// </summary> public class Observer : IObserver { public string ObserverName { get; private set; } public Observer(string name) { this.ObserverName = name; } public void Update() { Console.WriteLine("{0}: 增長了一個產品到倉庫", this.ObserverName); } } /// <summary> /// 客戶端調用 /// </summary> class program { static void Main(string[] args) { Subject subject = new Subject(); // 註冊一個觀察者 Observer observer1 = new Observer("Observer 1"); subject.Subscribe(observer1); // 2 subject.Subscribe(new Observer("Observer 2")); subject.Inventory++; //增長庫存 // 刪除一個觀察者,增長觀察者3 subject.Unsubscribe(observer1); subject.Subscribe(new Observer("Observer 3")); subject.Inventory++; Console.ReadLine(); } }
七、狀態模式(讓一個對象在其內部狀態改變的時候,其行爲也隨之改變。狀態模式須要對每個系統可能獲取的狀態創立一個狀態類的子類。當系統的狀態變化時,系統便改變所選的子類。)
這個比如瞌睡狀態的人要睡覺,睡醒了要幹活同樣,不一樣狀態下行爲不一樣。咱們以銀行ATM機去千流程的狀態作例子
/// <summary> /// ATM機對象 /// </summary> public class ATM { public ATMState currentState = null; public ATM() { currentState = new NoCardState(1000, this); //初始化atm機位沒卡狀態 } public void StartTheATM() { while (true) { Console.WriteLine(currentState.GetNextScreen()); //繼續下一個步驟 } } } /// <summary> /// 定義ATM機的狀態 /// </summary> public abstract class ATMState { private ATM atm; public ATM Atm { get { return atm; } set { atm = value; } } private int dummyCashPresent = 1000; public int DummyCashPresent { get { return dummyCashPresent; } set { dummyCashPresent = value; } } public abstract string GetNextScreen(); } /// <summary> /// 沒卡時的狀態實現 /// </summary> class NoCardState : ATMState { public NoCardState(ATMState state) : this(state.DummyCashPresent, state.Atm) { } public NoCardState(int amountRemaining, ATM atmBeingUsed) { this.Atm = atmBeingUsed; this.DummyCashPresent = amountRemaining; } public override string GetNextScreen() { Console.WriteLine("請輸入密碼"); string userInput = Console.ReadLine(); // 驗證改變當前狀態 if (userInput.Trim() == "1234") { UpdateState(); return "取多少錢啊?"; } return "沒驗證過"; } private void UpdateState() { Atm.currentState = new CardValidatedState(this); } } /// <summary> /// 驗證經過的狀態 /// </summary> class CardValidatedState : ATMState { public CardValidatedState(ATMState state) : this(state.DummyCashPresent, state.Atm) { } public CardValidatedState(int amountRemaining, ATM atmBeingUsed) { this.Atm = atmBeingUsed; this.DummyCashPresent = amountRemaining; } public override string GetNextScreen() { string userInput = Console.ReadLine(); int requestAmount; bool result = Int32.TryParse(userInput, out requestAmount); if (result == true) { if (this.DummyCashPresent < requestAmount) { return "atm沒那麼多錢給你取!"; } this.DummyCashPresent -= requestAmount; UpdateState(); //要麼進入沒錢狀態,要麼就進入吐錢狀態,篇幅有限,直接進入初始沒卡狀態算了 return string.Format(@" {0}錢被你取到了,回車繼續", requestAmount); } return "輸入正確數字"; } private void UpdateState() { //if (this.DummyCashPresent == 0) //{ // Atm.currentState = new NoCashState(this); //} //else //{ // Atm.currentState = new CashWithdrawnState(this); //} Atm.currentState = new NoCardState(this); } } /// <summary> /// 客戶端調用 /// </summary> class Program { static void Main(string[] args) { TestWithStatePattern(); } private static void TestWithStatePattern() { ATM atm = new ATM(); atm.StartTheATM(); } }
八、策略模式 (定義一個算法的系列,將其各個分裝,而且使他們有交互性。策略模式使得算法在用戶使用的時候能獨立的改變。)
狀態模式是對狀態對象的抽象,而策略模式是對狀態行爲(策略)的抽象。
/// <summary> /// 定義一個策略枚舉,可有可無,看你在應用環境中怎麼判斷 /// </summary> public enum ObjectToSort { StudentNumber, RailwayPassengers } /// <summary> /// 策略行爲基類 /// </summary> public interface ISortingStrategy { void Sort<T>(List<T> dataToBeSorted); } /// <summary> /// 策略行爲具體實現。快速排序 /// </summary> public class QuickSort : ISortingStrategy { public void Sort<T>(List<T> dataToBeSorted) { //邏輯代碼 } } /// <summary> ///策略行爲具體實現。 合併排序 /// </summary> public class MergeSort : ISortingStrategy { public void Sort<T>(List<T> dataToBeSorted) { //邏輯代碼 } } /// <summary> /// 客戶調用 /// </summary> class Program { static void Main(string[] args) { ISortingStrategy sortingStrategy = null; List<int> studentNumbers = new List<int> { 123, 678, 543, 189 }; sortingStrategy = GetSortingOption(ObjectToSort.StudentNumber); sortingStrategy.Sort(studentNumbers); List<string> railwayPassengers = new List<string> { "A21", "Z2", "F3", "G43" }; sortingStrategy = GetSortingOption(ObjectToSort.RailwayPassengers); sortingStrategy.Sort(railwayPassengers); } /// <summary> /// 調用環境 /// </summary> /// <param name="objectToSort"></param> /// <returns></returns> private static ISortingStrategy GetSortingOption(ObjectToSort objectToSort) { ISortingStrategy sortingStrategy = null; switch (objectToSort) { case ObjectToSort.StudentNumber: sortingStrategy = new MergeSort(); break; case ObjectToSort.RailwayPassengers: sortingStrategy = new QuickSort(); break; default: break; } return sortingStrategy; } }
九、模板方法模式(模板方法模式準備一個抽象類,將部分邏輯以具體方法及具體構造子類的形式實現,而後聲明一些抽象方法來迫使子類實現剩餘的邏輯。不一樣的子類能夠以不一樣的方式實現這些抽象方法,從而對剩餘的邏輯有不一樣的實現。先構建一個頂級邏輯框架,而將邏輯的細節留給具體的子類去實現。)
就是一個基類將共同部分實現,不一樣部分由不一樣的行爲邏輯實現。咱們以導出pdf和excel爲例
/// <summary> /// 模板基類 /// </summary> abstract class DataExporter { public void ReadData() { Console.WriteLine("從SqlServer中讀數據"); } public void FormatData() { Console.WriteLine("格式化每次請求的數據"); } // 這個基類根據導出的文件類型不一樣 有不一樣的實現方式 public abstract void ExportData(); // 客戶端將調用這個模板方法 public void ExportFormatedData() { this.ReadData(); this.FormatData(); this.ExportData(); } } /// <summary> /// 導出excel /// </summary> class ExcelExporter : DataExporter { public override void ExportData() { Console.WriteLine("導出數據到excel文件."); } } /// <summary> /// 導出pdf /// </summary> class PDFExporter : DataExporter { public override void ExportData() { Console.WriteLine("導出數據到pdf文件."); } } /// <summary> /// 客戶端調用 /// </summary> class Program { static void Main(string[] args) { DataExporter exporter = null; exporter = new ExcelExporter(); exporter.ExportFormatedData(); Console.WriteLine(); exporter = new PDFExporter(); exporter.ExportFormatedData(); } }
十、訪問者模式(封裝一些施加於某種數據結構元素之上的操做。一旦這些操做須要修改,接受這個操做的數據結構能夠保持不變。訪問者模式適用於數據結構相對穩定的系統,它把數據結構和做用於結構上的操做之間的耦合解脫開,使得操做集合能夠相對自由的演化。)
/// <summary> /// 基礎數據元素基類,穩定且可能不變的 /// </summary> public abstract class DocumentPart { public string Text { get; private set; } public abstract void Accept(IVisitor visitor); } /// <summary> /// 如下三個類的Accept方法都使用同一個訪問者,根據傳遞自身對象不一樣,而調用不一樣的訪問者中的重載操做方法 /// </summary> public class PlainText : DocumentPart { public override void Accept(IVisitor visitor) { visitor.Visit(this); //傳遞自身到訪問中方法中 } } public class BoldText : DocumentPart { public override void Accept(IVisitor visitor) { visitor.Visit(this); } } public class Hyperlink : DocumentPart { public string Url { get; private set; } public override void Accept(IVisitor visitor) { visitor.Visit(this); } } //結構對象 public class Document { private List<DocumentPart> m_parts; public void Accept(IVisitor visitor) { foreach (DocumentPart part in this.m_parts) { //2 文檔中的節點調用訪問中中的不一樣方法 part.Accept(visitor);//文檔中每一個節點都用一個訪問者對象 } } } /// <summary> /// 訪問者基類(做用域基礎結構的操做) /// </summary> public interface IVisitor { void Visit(PlainText docPart); void Visit(BoldText docPart); void Visit(Hyperlink docPart); } /// <summary> /// 訪問者具體實現類 /// </summary> public class HtmlVisitor : IVisitor { public string Output { get { return this.m_output; } set { m_output = value; } } private string m_output = ""; public void Visit(PlainText docPart) { this.Output += docPart.Text; } public void Visit(BoldText docPart) { this.m_output += "<b>" + docPart.Text + "</b>"; } public void Visit(Hyperlink docPart) { this.m_output += "<a href=\"" + docPart.Url + "\">" + docPart.Text + "</a>"; } } /// <summary> /// 客戶端調用 /// </summary> class Program { static void Main(string[] args) { Document doc = new Document(); HtmlVisitor visitor = new HtmlVisitor(); doc.Accept(visitor); //1 這裏把訪問者傳遞給結構對象 Console.WriteLine("Html:\n" + visitor.Output); } }
看完記得下邊點贊,費心費神,給點精神鼓勵!!!!!!!!