yangyang

a .NET Developer

DotNet Framework


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

C#设计模式之装饰模式

假设我们要扩展同事编写的某个类的某些功能,怎样在不修改类的前提下,增加新的功能呢?有一种方法是使用继承,编写一个继承自该基类的子类,然后添加新的方法,或者重写父类里面的某些方法或属性。 问题在于,在有些情况下,并不能继承。最常见的是这个类无法继承,要么是我们编写的类,需要继承自其他类,而在C#里面,不允许多各类继承,再就是这类是封闭的Sealed,无法继承。 Decorator装饰模式,可以使得我们扩展已经存在的类,而不需要修改已经存在类的代码,并且避免了继承导致产生过多子类。下面用一个例子来说明装饰模式。 自定义字符串构造器 假设我们要做一个代码生成器的功能,需要扩展StringBuilder,来增加缩进功能。首先想到的是直接继承自StringBuilder类,但是出于安全原因,这个类是Sealed封闭类,另外,还要保存当前缩进的级别用来给方法 …

Design Pattern Decorator Pattern Dynamic Decorator Static Decorator Decorator Composition