IT科技类资讯

值得收藏的 C# 设计模式套路之三

时间:2010-12-5 17:23:32  作者:人工智能   来源:IT科技  查看:  评论:0
内容摘要:本文转载自微信公众号「老王Plus」,作者老王Plus的老王。转载本文请联系计老王Plus公众号。行为设计模式跟前两种模式从内容上是有区别的。行为设计模式更关注对象之间的通信,以及职责和任务的交互。一

本文转载自微信公众号「老王Plus」,收藏设计作者老王Plus的模式老王。转载本文请联系计老王Plus公众号。套路

行为设计模式跟前两种模式从内容上是收藏设计有区别的。行为设计模式更关注对象之间的模式通信,以及职责和任务的套路交互。

一、收藏设计责任链

名称起得很明显,模式 就是套路一个链式的责任或任务。为什么要链式呢?收藏设计是因为请求要沿着多个处理程序往后传递。一个任务,模式可能要分很多步,套路又不想把所有的收藏设计步骤耦合到一个处理程序中处理,就会用到这个套路。模式

看看代码:

public interface IHandler {      public IHandler SetNext(IHandler handler);     public object Handle(object input); } public class Handler : IHandler {      private IHandler _handler;     public IHandler SetNext(IHandler handler)     {          _handler = handler;         return handler;     }     public virtual object Handle(object input)     {          return _handler?套路.Handle(input);     } } public class HandlerA : Handler {      public override object Handle(object input)     {          if (input as string == "A")         {              Console.WriteLine("HandlerA : just return");             return true;         }         Console.WriteLine("HandlerA : call next handler");         return base.Handle(input);     } } public class HandlerB : Handler {      public override object Handle(object input)     {          if (input as string == "B")         {              Console.WriteLine("HandlerB : just return");             return true;         }         Console.WriteLine("HandlerB : call next handler");         return base.Handle(input);     } } public class HandlerC : Handler {      public override object Handle(object input)     {          if (input as string == "C")         {              Console.WriteLine("HandlerC : just return");             return true;         }         Console.WriteLine("HandlerC : end");         return base.Handle(input);     } } public static class Example {      public static void Test()     {          var handlerA = new HandlerA();         var handlerB = new HandlerB();         var handlerC = new HandlerC();         handlerA.SetNext(handlerB).SetNext(handlerC);         var resultOne = handlerA.Handle("A");         var resultTwo = handlerA.Handle("B");         var resultThree = handlerA.Handle("C");         var resultFour = handlerA.Handle("D");     }     // results A:     // HandlerA : just return     // results B:     // HandlerA : call next handler     // HandlerB : just return     // results C:     // HandlerA : call next handler     // HandlerB : call next handler     // HandlerC : just return     // results D:     // HandlerA : call next handler     // HandlerB : call next handler     // HandlerC : end } 

这里面,重要的是 handlerA.SetNext(handlerB).SetNext(handlerC) 一句。这个在限定链的方向和内容。能理解到这一层,就算是真懂了。

二、命令

这个网上内容很多,高防服务器Command,通常会跟 Delegate、Event 一起说。

咱们这儿单说这个命令模式。

命令模式是一个非常常用的模式。它的作用,是把请求转换为对象,以便我们可以异步、延迟、队列或者参数化请求,以及做一些可撤销的工作。

代码套路特别简单:

public interface ICommand {      public void Execute(); } public class DemoCommand : ICommand {      private readonly string _parameter;     public DemoCommand(string parameter)     {          _parameter = parameter;     }     public void Execute()     {          Console.WriteLine(_parameter);     } } public static class Invoker {      public static void SendAction(ICommand command)     {          command.Execute();     } } public static class Example {      public static void Test()     {          var command = new DemoCommand("Hello WangPlus");         Invoker.SendAction(command);     }     // results:     // Hello WangPlus } 

这个 Command 的应用场景特别多,建议大家理解透彻。我们在做 SDK 或 类库的时候,会经常有类库内实现业务逻辑,而调用端实现数据交互的情况,用的就是命令模式。举个例子说:做个认证授权的类库,库里面去实现鉴权和生成 Token 的工作,调用端去判断登录帐号密码的验证。源码下载这样做,这个库才能是一个跟数据库和帐号体系无关的通用库。

三、迭代器

这也是一个用得很多的模式。

它最主要的作用,就是遍历集合的元素;而最主要的特性,就是不会暴露数据本身。

看代码:

public abstract class IteratorBase {      public abstract bool EndOfDocument();     public abstract object Next();     public abstract object First();     public abstract object Current(); } public class Iterator : IteratorBase {      private readonly List<object> _customList;     private int current = 0;     public Iterator(List<object> customList)     {          _customList = customList;     }     public override bool EndOfDocument()     {          if (current >= _customList.Count - 1) return true;         return false;     }     public override object Current()     {          return _customList[current];     }     public override object Next()     {          if (current < _customList.Count - 1) return _customList[++current];         return null;     }     public override object First()     {          return _customList[0];     } } public static class Example {      public static void Test()     {          var demolist = new List<object>() {  "a", "b", "c", "d" };         var iterator = new Iterator(demolist);         var item = iterator.First();         while (item != null)         {              Console.WriteLine(item);             item = iterator.Next();         }         if (iterator.EndOfDocument()) Console.WriteLine("Iterate done");     }     //results:     // a     // b     // c     // d     // Iterate done } 

如果想了解迭代器的原理、异步及更深的应用,可以去看看我专门讲迭代器的文章一文说通C#中的异步迭代器

四、解释器

这也是行为模式中一个常用的模式,它主要是根据上下文来获取不同的类型和行为。换句话说,相同的内容,针对不同的云南idc服务商类型,采取不同的行为。

通常这个模式,用得最多的是多语言的场景。

public class Context {      public string Value     {          get;         private set;     }     public Context(string value)     {          Value = value;     } } public abstract class Interpreter {      public abstract void Interpret(Context context); } public class EnglishInterpreter : Interpreter {      public override void Interpret(Context context)     {          switch (context.Value)         {              case "1":                 Console.WriteLine("One");                 break;             case "2":                 Console.WriteLine("Two");                 break;         }     } } public class ChineseInterpreter : Interpreter {      public override void Interpret(Context context)     {          switch (context.Value)         {              case "1":                 Console.WriteLine("一");                 break;             case "2":                 Console.WriteLine("二");                 break;         }     } } public static class Example {      public static void Test()     {          var interpreters = new List<Interpreter>() {              new EnglishInterpreter(),             new ChineseInterpreter()         };         var context = new Context("2");         interpreters.ForEach(c => c.Interpret(context));     }     // results:     // two     // 二 } 

上面这个例子是解释器的标准套路。通常我们用的时候,可以配合抽象工厂模式,根据上下文独立加载单个的解释器,这样就能实现类似根据浏览器的设定语言来显示界面语言的代码。

如果用微软的标准库来实现,那这个解释器和抽象工厂已经被包在了库里,使用时只需定义语言对照表就成。但内里的逻辑,还是这个。

五、中介

注意,是中介,不是中间件。这是两个东西,别用混了。

不过,两个原理上有一点相像。中介模式,目的是解耦对象之间的直接通信,并转为从中介对象来传递消息。

也是看代码:

public interface IMediator {      public void Send(string message, Caller caller); } public class Mediator : IMediator {      public CallerA CallerA     {          get;         set;     }     public CallerB CallerB     {          get;         set;     }     public void Send(string message, Caller caller)     {          if (caller.GetType() == typeof(CallerA))         {              CallerB.ReceiveRequest(message);         }         else         {              CallerA.ReceiveRequest(message);         }     } } public abstract class Caller {      protected readonly IMediator _mediator;     public Caller(IMediator mediator)     {          _mediator = mediator;     } } public class CallerA : Caller {      public void SendRequest(string msg)     {          _mediator.Send(msg, this);     }     public void ReceiveRequest(string msg)     {          Console.WriteLine("CallerA Received : " + msg);     }     public CallerA(IMediator mediator) : base(mediator) {  } } public class CallerB : Caller {      public void SendRequest(string msg)     {          _mediator.Send(msg, this);     }     public void ReceiveRequest(string msg)     {          Console.WriteLine("CallerB Received : " + msg);     }     public CallerB(IMediator mediator) : base(mediator) {  } } public static class Example {      public static void Test()     {          var mediator = new Mediator();         var callerA = new CallerA(mediator);         var callerB = new CallerB(mediator);         mediator.CallerA = callerA;         mediator.CallerB = callerB;         callerA.SendRequest("Hello");         callerB.SendRequest("WangPlus");     }     // results:     // CallerB Received : Hello     // CallerA Received : WangPlus } 

CallerA 和 CallerB 之间没有直接通信,而是经由中介 Mediator 进行了消息传递。

这个模式,最常用的场景是两个现成的类库之间要实现通讯,而不想或没办法修改这两个类库的代码,就可以做一个中介库,来进行数据传递。

六、备忘录

跟名字一样。备忘录模式主要是用来保存对象的状态,并将状态封装,以便在需要时,恢复到前边的状态。

套路是这样的:

public class Memento {      private readonly string _state;     public Memento(string state)     {          _state = state;     }     public string GetState()     {          return _state;     } } public class Originator {      public string State     {          get;         set;     }     public Originator(string state)     {          State = state;     }     public Memento CreateMemento()     {          return new Memento(State);     }     public void RestoreState(Memento memento)     {          State = memento.GetState();     } } public class Taker {      private Memento _memento;     public void SaveMemento(Originator originator)     {          _memento = originator.CreateMemento();     }     public void RestoreMemento(Originator originator)     {          originator.RestoreState(_memento);     } } public static class Example {      public static void Test()     {          var originator = new Originator("First State");         var careTaker = new Taker();         careTaker.SaveMemento(originator);         Console.WriteLine(originator.State);         originator.State = "Second State";         Console.WriteLine(originator.State);         careTaker.RestoreMemento(originator);         Console.WriteLine(originator.State);     }     // results:     // First State     // Second State     // First State } 

这个代码看着复杂,其实核心就一点:在改变状态前,先把状态在对象之外保存下来。

你细品。

七、观察者

观察者模式主要处理的是对象间一对多的通信。如果一个对象的状态发生了变化,依赖对象会发出通知并进行更新。

public class Updater {      public string NewState     {          get;     }     private readonly List<ObserverBase> _observers = new List<ObserverBase>();     public Updater(string newState)     {          NewState = newState;     }     public void AddObserver(ObserverBase observerBase)     {          _observers.Add(observerBase);     }     public void BroadCast()     {          foreach (var observer in _observers)         {              observer.Update();         }     } } public abstract class ObserverBase {      public abstract void Update(); } public class Observer : ObserverBase {      private readonly string _name;     public string State;     private readonly Updater _updater;     public Observer(string name, string state, Updater updater)     {          _name = name;         State = state;         _updater = updater;     }     public override void Update()     {          State = _updater.NewState;         Console.WriteLine($"Observer { _name} State Changed to : " + State);     } } public static class Example {      public static void Test()     {          var updater = new Updater("WangPlus");         updater.AddObserver(new Observer("1", "WangPlus1", updater));         updater.AddObserver(new Observer("2", "WangPlus2", updater));         updater.AddObserver(new Observer("3", "WangPlus3", updater));         updater.BroadCast();     }     // results:     // Observer 1 State Changed to : WangPlus     // Observer 2 State Changed to : WangPlus     // Observer 3 State Changed to : WangPlus } 

好吧,这个代码各上面备忘录模式的代码有点像。事实上,这两个模式的主要区别,一个是一对一,一个是一对多。

至于为什么两个模式的名称区别这么大,说实话,我也不知道。在我的概念中,这两个模式是可以混着用的。经验来说,备忘录模式我用得更多些。

八、状态

状态模式也是一个常用的模式。

状态模式,和最前面的责任链模式,两个有点类似。状态模式更直接,就是状态改变时,同步改变行为。

这两个模式,在很多情况下,可以有效减少 if…else 的分支数量。所以,看上去就又高大上了:)

上套路:

public interface IState {      public void Handle(Context context); } public class StateA : IState {      public void Handle(Context context)     {          context.State = new StateB();     } } public class StateB : IState {      public void Handle(Context context)     {          context.State = new StateA();     } } public class Context {      private IState _state;     public IState State     {          get => _state;         set         {              _state = value;             Console.WriteLine("State: " + _state.GetType().Name);         }     }     public Context(IState state)     {          State = state;     }     public void Action()     {          State.Handle(this);     } } public static class Example {      public static void Test()     {          var context = new Context(new StateA());         context.Action();         context.Action();         context.Action();         context.Action();     }     // results:     // State: StateA     // State: StateB     // State: StateA     // State: StateB     // State: StateA } 

看懂了吗?

如果把里面的 IState 换成 IHandler,那就是一个责任链。区别就是一个是数据,一个是方法,除此之外都一样。

所以,还是我老说的那句话:不要关心名称,要关心实质。在现代开发中,数据、方法、对象,其实都在趋向大一统的。明白这个道理,你就通了。

九、策略

策略模式主要是用来封装算法族并使它们可互换,所以它们可以独立地进行更改,而不需要任何紧密耦合。

对,又是一个以解耦为目的的架构。

public interface IStrategy {      public void AlgorithmAction(); } public class AlgorithmStrategyA : IStrategy {      public void AlgorithmAction()     {          Console.WriteLine("This is Algorithm A");     } } public class AlgorithmStrategyB : IStrategy {      public void AlgorithmAction()     {          Console.WriteLine("This is Algorithm B");     } } public class Context {      private readonly IStrategy _strategy;     public Context(IStrategy strategy)     {          _strategy = strategy;     }     public void GeneralAction()     {          _strategy.AlgorithmAction();     } } public static class Example {      public static void Test()     {          var context = new Context(new AlgorithmStrategyA());         context.GeneralAction();         context = new Context(new AlgorithmStrategyB());         context.GeneralAction();     }     // results:     // This is Algorithm A     // This is Algorithm A } 

这个模式的核心是上下文中的 IStrategy,这本身是一个抽象,这个抽象对应的实体里,才是算法的实现。

一个标准的模式。

十、模板

模板模式是面向对象的一个基础模式,应用也非常广。

这个模式类似于抽象工厂模式,在基类上建立整体的操作结构,并根据需求的变动,在子类中重写一些操作。

听着很复杂,其实代码一看就明白:

public abstract class TemplateBase {      public void Operate()     {          FirstAction();         SecondAction();     }     private void FirstAction()     {          Console.WriteLine("First action from template base");     }     protected virtual void SecondAction()     {          Console.WriteLine("Second action from template base");     } } public class TemplateA : TemplateBase {  } public class TemplateB : TemplateBase {      protected override void SecondAction()     {          Console.WriteLine("Second action from template B");     } } public class TemplateC : TemplateBase {      protected override void SecondAction()     {          Console.WriteLine("Second action from template B");     } } public static class Example {      public static void Test()     {          var templateMethodA = new TemplateA();         var templateMethodB = new TemplateB();         var templateMethodC = new TemplateC();         templateMethodA.Operate();         templateMethodB.Operate();         templateMethodC.Operate();     }     // results:     // First action from template base     // Second action from template base     // First action from template base     // Second action from template B     // First action from template base     // Second action from template B } 

很简单,对吧?

十一、访问者

访问者模式,是上面模板模式的一个变形,目的一样,在不修改基类代码的情况下,向子类的层次结构中添加新的方法和行为。

看代码:

public interface IVisitor {      public void VisitItem(ItemBase item); } public class VisitorA : IVisitor {      public void VisitItem(ItemBase item)     {          Console.WriteLine("{ 0} visited by { 1}", item.GetType().Name, this.GetType().Name);     } } public class VisitorB : IVisitor {      public void VisitItem(ItemBase item)     {          Console.WriteLine("{ 0} visited by { 1}", item.GetType().Name, this.GetType().Name);     } } public abstract class ItemBase {      public abstract void Accept(IVisitor visitor); } public class ItemA : ItemBase {      public override void Accept(IVisitor visitor)     {          visitor.VisitItem(this);     }     public void ExtraOperationA() {  } } public class ItemB : ItemBase {      public override void Accept(IVisitor visitor)     {          visitor.VisitItem(this);     }     public void ExtraOperationB() {  } } public class StructureBuilder {      readonly List<ItemBase> _items = new List<ItemBase>();     public void AddItem(ItemBase element)     {          _items.Add(element);     }     public void Accept(IVisitor visitor)     {          foreach (var item in _items)         {              item.Accept(visitor);         }     } } public static class Example {      public static void Test()     {          var structure = new StructureBuilder();         structure.AddItem(new ItemA());         structure.AddItem(new ItemB());         structure.Accept(new VisitorA());         structure.Accept(new VisitorB());     }     //results:     //ItemA visited by VisitorA     //ItemB visited by VisitorA     //ItemA visited by VisitorB     //ItemB visited by VisitorB } 

访问者模式扩展了模板模式,扩展性、复用性、灵活性更好,而且非常体现单一职责原则。

十二、总结

模式套路这就算是写完了,居然用了三篇文章才写完。

有没有感觉?所有的模式,都是为了解耦。解耦的目的,是为了把一个系统分成更细的组件。细分组件更适合大团队的开发。而大团队的技术架构,更容易在网上的各种文章中有所体现。

所以,也跟大家提个醒:所有的架构都是需要熟悉和掌握的,这叫面试必备的知识。在实际应用中,如果架构熟悉,所有的程序看着会更富有逻辑,而如果不熟悉架构,那看使用架构写出来的代码,会是一场恶梦。

成长在于一点点的积累,于大家,于我,都一样。

copyright © 2025 powered by 益强资讯全景  滇ICP备2023006006号-31sitemap