Web Analytics
yangyang

码农兼一个普普通通小青年

Design Patterns


使用可变参数模板和CRTP实现访问者模式

Visitor模式的一大缺点就是依赖问题,在定义Visitor接口的时候,就必须要知道所有的子类类型。在一些编译链接型语言如C++中,Visitor类和子类就会出现相互依赖的情况,当然,通过前向声明可以解决这个问题。另外一个问题就是在不同的子类中有很多“制式”代码。比如所有的子类必须实现基类中的Accept(Visitor&)方法,并且方法的实现都是一模一样的,都是调用该参数的Visitor方法并传入指向对象本身的引用。幸好在C++ 11中引入了可变参数模板,使用可变参数模板以及CRTP技术,可以极大简化Visitor模式中的一些实现方面的问题。在这一过程中顺便学习和了解Moden C++的一些强大的功能,这些功能是如此的特别以至于它跟C#有很大的不同。 …

visitor variadic-templates CRTP

C++中的可变参数模板

本来是想接着上文继续来说明如何使用C++模板来简化Visitor设计模式的,但这里涉及到了C++ 11中引入的可变参数模板,这个特性很有用,所以值得专门写一篇文章来介绍一下C++中的可变参数模板。可变参数模版比较特殊,跟其它语言比如C#里面的params相比,似乎更加灵活和强大。 当然我没有能力对某个特性做全面的解读,可变参数模板有很多用处,这里列举了侯捷老师在《 C++新标准:C++11&14》课程里对可变参数模版的解读里面举的几个例子,这几个例子比较经典,完美的解释了可变参数模版的用法。这篇文章算是一个简单的笔记,C++里面有些特性需要反复的学习和复习才能掌握。 …

variadic-templates tuple CPulsPlus parameter pack

从双分发的视角看访问者模式

在23种经典设计模式中,Visitor模式可能是比较难理解的几个模式之一,之前在C#设计模式之访问模式这篇文章中渐进式的介绍了Visitor设计模式。恰巧最近看的《C++语言设计与演化,简称D&E》这本书中提到了一个单分派和双分派的概念,这里从前文介绍的C++中的虚函数表以及动态分发即单分发的基础上,介绍双分发以及基于双分发的Visitor设计模式,试着从另外一个角度来看访问者这一经典的设计模式,最后对比了通过工厂方法和访问者模式的异同。 …

Design Pattern Double Dispatch single dispatch visitor vtable factory

一些有关Excel的小技巧

在日常工作中的有些需求,比如数据分析和预处理,通过其它工具比如Excel点点鼠标也能解决,而且可能比写代码还快。Excel有很多强大的功能,这里只简单介绍一下我在Excel里面用到的一些小功能。这些功能包括,分列,函数,高级复制粘贴,以及数据透视表 …

Pivot Table

从单元测试来对代码逻辑进行改进

这个例子来源于Pro ASP.NET Core 3这一本书,书中介绍了对ASP.NET Core程序进行单元测试的方法,其中有一例,在对购物车逻辑模块进行功能开发的时候,发现单元测试很“吃力”,后面得到了如何对其进行优化,从而大大简化了单元测试的方法。所以这里记录一下。 购物车的实现     这里只是一个简单的购物车实现,用户在挑选物品放进购物车的时候,将数据临时存放在了Session中(缺点是如果服务器重启,数据会丢失,这里不讨论)。购物车的模型Cart如下: public class Cart { public List<CartLine> Lines { get; set; } = new List<CartLine>(); public virtual void AddItem(Product product, int quantity) { …

UnitTest SRP

C#设计模式之观察者模式

观察者模式,简单来说就是一个组件在状态发生变化的时候,可以通知其它组件。观察者模式用途很广,比如在UI界面中,当绑定的数据对象发送改变,UI会跟着发送改变。观察者模式是一种很常见和必要的模式,C#的设计者通过关键字event来简化对观察者模式的使用。它的基本用法是,首先使用event关键字定义事件,然后注册事件回调方法EventHandler,回调方法通常包含两个参数,一个object类型的sender和一个继承自EventArgs的参数,该参数携带一些触发事件的必要信息。     event事件其实是对委托的包装,就像Action和Func是对lamda表达式的包装一样。对event的包装成为EventHandler,有泛型和非泛型版本,泛型主要是继承自EventArgs的类型。     下面举个例子说明:假设人病了需要去看医生。首先要定义看医生时要提供的信息,在这个例子中只需要告诉医生 …

Design Pattern Observer Pattern Event Stream

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