yangyang

a .NET Developer

Design Patterns


C#设计模式之中介者模式

大部分应用程序通常包含多个组件,这些组件之间通常通过直接引用来进行通讯。但是在某些情况下,并不想某个组件知道其他组件的存在,或者即使知道,也不要通过直接引用的方式来进行通讯或交互,因为这种直接引用的方式就会产生依赖,从而会扩展对象的生命周期,除非通过弱引用的方式来进行。     中介者模式是一种遍历多个组件之间通讯或交互的模式。他用一个中介对象封装一系列的对象交互,中介者使各对象不需要显示地相互作用,从而使耦合松散,而且可以独立地改变它们之间的交互。     使用中介模式,对象之间的交互将封装在中介对象中。对象不再直接相互交互(解耦),而是通过中介进行交互。这减少了对象之间的依赖性,从而减少了耦合。     中介者模式的优点就是减少类间的依赖,把原有的一对多的依赖变成了一对一的依赖,同事类只依赖中介者,减少了依赖,当然同时也降低了类间的耦合;缺点就是中介者会膨胀得很大,而且逻辑复杂,原本 …

Design Pattern Mediator Pattern MediatR

C#设计模式之访问模式

Visitor 是面向对象设计模英中一个很重要的设计模款,这个模式是一种将数据操作和数据结构分离的一种方法,它能够在不修改结构的情况下向现有对象结构添加新操作,是遵循开放/封闭原则的一种方法。上述这个定义很枯燥抽象,那就以例子来说明吧。     假设我们要打印四则运算表达式,比如(1.0+(2.0+3))的字符串表示,或者对其求值,这是两个需求,一个是打印,一个是求值。为了简化,这里仅对加号括号进行处理,其他的可以类推。在写任何代码之前,一定要考虑一下是否面向对象,针对上面的字符串,可以将数字和操作符抽象为两个对象,并实现同一抽象类Expression。 public abstract class Expression { }     目前上述Expression抽象类没有任何成员或方法,后续我们会添加。接着添加表示doule类型数字的具体类DoubleValueExpression,和 …

Design Pattern Visitor Pattern Double Dispatch

C#设计模式之状态模式

状态模式是一种行为设计模式, 让你能在一个对象的内部状态变化时改变其行为, 使其看上去就像改变了自身所属的类一样。状态模式与有限状态机的概念紧密相关。其主要思想是程序在任意时刻仅可处于几种有限的状态中。 在任何一个特定状态中, 程序的行为都不相同, 且可瞬间从一个状态切换到另一个状态。 不过, 根据当前状态, 程序可能会切换到另外一种状态, 也可能会保持当前状态不变。 这些数量有限且预先定义的状态切换规则被称为转移。      其实在之前的文章熔断器设计模式中,就是状态模式的很典型应用,系统有三种状态,闭合状态,此时系统能正常运行,当发生错误,且错误次数达到阈值时,会进入到断开状态,当断开状态持续一定时间,系统会进入到半闭合状态,此时能运行请求处理,当请求处理成功,成功次数达到阈值,则进入闭合状态,否则如果仍然失败,则会退回断开状态,系统不处理请求,直接返回错误,在那篇文章里,有详细代码演 …

Design Pattern State Pattern

C#设计模式之备忘录模式

在之前的命令模式中,我们可以保存所有的对系统的状态修改的命令,通过按顺序执行命令的方式,使得系统能够回滚到之前的任何一个时点,这种回滚是累积式的。     但是在某些情况下,我们并不关心这种“回放”,我们只关心如何将系统回滚到特定的某一个状态即可。备忘录模式非常像快照,我们给系统在某一时刻进行拍照,保存其所以需要的状态,从而在后续某个需要的时间点可以进行恢复。 ▲ 图片来自 https://refactoring.guru/design-patterns/memento     以前面在讨论命令模式的银行账户的例子来看,我们需要保存的状态为银行账户的余额,所以需要将资金字段balance保存起来,但是这里有个问题,资金应该是银行账户BankAccount的内部字段,不应该提供给外部直接访问,因为这样会破坏封装性,但是要保存快照就必须要能访问到这个私有字段。一个解决方法是,使用内部类来实现 …

Design Pattern Memento Pattern

C#设计模式之策略模式

策略模式是一种行为设计模式, 它能让你定义一系列算法, 并将每种算法分别放入独立的类中, 以使算法的对象能够相互替换。这么说还有点抽象,这里就举个例子。假设我们需要输出一个字符串列表,比如以如下列表方式输出: just like this     随着需求的变更,可能需要输出不同的格式,比如增加一些特殊符号,比如如果要输出列表,则需要在用"<ul>"或者"<li>"来对字符串进行包装,再比如在HTML或者JSON格式中,需要输出一些起始标签或者结束标签。     所以我们可以抽象出一种输出列表格式的策略: 渲染开始标签或者元素 渲染列表中的每一个对象 渲染结束标签或者元素     不同的策略,可能有不同的格式,但是流程是通用的。     根据策略能否在运行时动态替换,策略模式有两种形式,分别是动态策略和静态策略模式。 动态策略模式     我们的目标是以两种格式输出列表: …

Design Pattern Strategy Pattern

C#设计模式之命令模式

命令模式(command)简单来说就是将一系列的请求命令封装成对象,而不是直接调用真正执行者的方法,真正的执行由这个封装好的对象来执行,这样比较好扩展。比如我们在应用里面,经常会用到复制粘贴操作,这个操作可以由主菜单下面的按钮发出,也可以由快捷工具栏的按钮发出,也可以由快捷键Ctrl+C、Ctrl+V产生,这些不同的请求者发出的改变行为是一样的,如果各自都直接进行操作,就会使得代码逻辑重复,并且在执行一些撤销Undo或者重做Redo操作时就比较难以实现。    另外,在一些应用场景下,我们需要记录修改之前的值,以便于事后进行审计,或者回滚到之前的值等等。这种普通的直接对对像进行修改或者执行某种逻辑的方式,就无法扩展我们自定义的逻辑,比如日志、审计等等。 场景     假设我们需要对一个允许透支的银行账户进行建模,这个对象包含了两个方法,存款Deposit和取款Withdraw操作。 …

CQRS Command Pattern Design Pattern

C#设计模式之职责链模式

在软件开发中,我们通常会遇到一种场景,比如某个请求,会依次经过系统中的很多个模块来处理,如果某个模块处理不了,则将请求传递给下一个模块,比如在订单处理中,首先要经过用户校验,商品库存充足校验,如果不满足条件,返回错误,如果满足条件才会到下一步处理。     在ASP.NET Core里有middleware中间键的概念,每一个请求进来,都会经过一系列的Handler,这是一种职责链模式,每一个Handler都会决定是否处理该请求,以及是否决定将该请求传递给一下请求继续处理。     在.NET的委托中,也有一个委托链概念,当多个对象注册同一事件时,对象将委托放在一个链上,依次处理。     在JavaScript或者WPF的事件模型中,事件有冒泡和下沉,事件能够逐个向上级或者下级对象传递,每个对象都会决定是否会对该事件进行回应,或者终止事件的继续传递。     这些都是典型的职责链模式,责 …

Design Pattern Chain of Responsibility

C#设计模式之适配器模式

适配器模式,简单来说,就是将一个类的接口转换为另外一个类的接口,使得原本由于接口不兼容而不能一起工作的那些类能够一起工作。在现实生活中,这种例子也很多,比如我们如果买的是港行的电器,比如港版的iPhone,英版的原版树莓派,那么自带的充电器插头可能就是英标,在国内不能直接使用,国标的插头间距跟英标不兼容,所以,就需要一个适配器。 ▲ 不同标准插头的适配 还有个现实生活中的,比如我的车是个低配的绒布座椅,可以换更高级一点车的座椅,但是座椅的宽度可能不一样,那么就需要加一个滑轨适配器,一头把滑轨固定到车子上,一头就可以连接新更宽的座椅。 ▲ 不同宽度汽车座椅的兼容安装 还有个更有意思的图,下面这个😂。 ▲ 汽车到铁轨转换器,图片来自 https://refactoring.guru/ 场景 现在来说说软件开发中的一些场景,假设我们有一个基础绘 …

Design Pattern Adapter Pattern

C#设计模式之桥接模式

在软件设计中,有一个很常见的问题是&ldquo;状态空间爆炸&rdquo;(state space explosion),即同一个对象的多个不想关的实体,用来表示所有可能的状态时,就会出现笛卡尔乘积式的问题。比如,假如我们有不同颜色的红色、蓝色(状态1)不同形状的(状态2)圆形、矩形对象,就要写四个类,比如RedSquare、BlueSquare、RedCircle、BlueCircle。如果增加一种形状,就要增加2个类,增加一种颜色,也要增加2各类。 我们要做的其实就是把一个事物的两个方面&ldquo;组合&rdquo;在一起,有多种方法能实现这一点,例如,如果颜色是一个简单特性,我们可以将颜色定义为枚举,如果颜色是可变属性、字段或行为我们就不能把他定义为枚举了。如果硬要这么做,要么代码里会出现很多if..else或者switch,这些分支语句里包含了其他一些不想关 …

Design Pattern Bridge Pattern

C#设计模式之享元模式

Flyweight,fly是苍蝇的意思,拳击里有个&ldquo;蝇量级&rdquo;,翻译也是&ldquo;flyweight&rdquo;,在设计模式中,Flyweight被翻译成了&ldquo;享元&rdquo;,意思是&ldquo;共享元素&rdquo;。在一些需要大量小的对象的应用场景,如果想要减少内存占用,可以考虑享元模式。下面举两个例子说明。 Example 1:人名的存储 比如,在英语国家,有很多人叫&ldquo;John Smith&rdquo;,如果我们在系统里,就要存储这个名字很多次,那么就需要很多额外的内存来存储相同的名字。相反,如果我们能够只存储某个名字一次,然后其余的都引用这个名字,这样就会节省很多空间。 再比如,可能&ldquo;Smith&rdquo;这个姓有很多人用,那么就可以将名字&ldquo;John&rdquo;和姓& …

Design Pattern Flyweight Pattern