C#开发基础学习-值得收藏的 C# 设计模式
小职 2021-12-08 来源 :「老王Plus」 阅读 1185 评论 0

摘要:本篇主要介绍了C#开发基础学习-值得收藏的 C# 设计模式,通过具体的内容展现,希望对C#开发的学习有一定的帮助。

本篇主要介绍了C#开发基础学习-值得收藏的 C# 设计模式,通过具体的内容展现,希望对C#开发的学习有一定的帮助。

C#开发基础学习-值得收藏的 C# 设计模式

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

 

一、责任链

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

 

看看代码:

 

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#中的异步迭代器

 

四、解释器

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

 

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

 

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

}

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

 

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

 

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


✅  扫码免费获取IT基础课程 · IT技术干货 · 答疑解惑 · 职业测评

C#开发基础学习-值得收藏的 C# 设计模式


本文由 @小职 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程