一页中总结行为类型的设计模式
前两篇总结了创建类型的设计模式和结构类型的设计模式。这是模式总结的最后一篇,即行为类型的模式,它主要是关于类及对象的交互相关的。
行为类型的设计模式目录
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(); } }
2、命令模式(将一个请求封装为一个对象,从而使你可用不同的请求参数化;对请求排队或记录请求日志,以及支持可取消的操作。)
命令模式因为解耦了请求和执行之间的关系,所以中间封装了一层命令对象,在封装的具体命令实现类中可以实现诸如排队、撤销执行和作为回掉函数使用等
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(); } }
3、迭代器模式(提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示。)
迭代器模式是专门针对集合类类似的聚合对象的。见示例
/// <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(); } }
4、中介者模式(包装了一系列对象相互作用的方式,使得这些对象不必相互明显作用,从而使它们可以松散偶合。当某些对象之间的作用发生改变时,不会立即影响其他的一些对象之间的作用,保证这些作用可以彼此独立的变化。)
其实中介者模式就是对两个相互作用的对象中间增加一个中间处理环节对象来协调两者之间的作用关系。例如以下例子使用同事间发送消息为例
//参与者基类 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中介发出一条信息"); } }
5、备忘录模式(备忘录对象是一个用来存储另外一个对象内部状态的快照的对象。备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态捉住,并外部化,存储起来,从而可以在将来合适的时候把这个对象还原到存储起来的状态。适合回滚操作)
//备忘录实体对象,存储发起人对象的状态 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 } }
6、观察者模式(在对象间定义一个一对多的联系性,由此当一个对象改变了状态,所有其他相关的对象会被通知并且自动刷新。)
这个模式有点类似中介者模式,但是不能混淆了,中介者模式是多对多关系的,观察者模式是一对多关系,理解了这个关系,就不难理解观察者模式。
/// <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(); } }
7、状态模式(让一个对象在其内部状态改变的时候,其行为也随之改变。状态模式需要对每一个系统可能获取的状态创立一个状态类的子类。当系统的状态变化时,系统便改变所选的子类。)
这个好比瞌睡状态的人要睡觉,睡醒了要干活一样,不同状态下行为不同。我们以银行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(); } }
8、策略模式 (定义一个算法的系列,将其各个分装,并且使他们有交互性。策略模式使得算法在用户使用的时候能独立的改变。)
状态模式是对状态对象的抽象,而策略模式是对状态行为(策略)的抽象。
/// <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; } }
9、模板方法模式(模板方法模式准备一个抽象类,将部分逻辑以具体方法及具体构造子类的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。先构建一个顶级逻辑框架,而将逻辑的细节留给具体的子类去实现。)
就是一个基类将共同部分实现,不同部分由不同的行为逻辑实现。我们以导出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(); } }
10、访问者模式(封装一些施加于某种数据结构元素之上的操作。一旦这些操作需要修改,接受这个操作的数据结构可以保持不变。访问者模式适用于数据结构相对稳定的系统,它把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作集合可以相对自由的演化。)
/// <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); } }
看完记得下边点赞,费心费神,给点精神鼓励!!!!!!!!