# 设计模式学习 **Repository Path**: csqs/design-pattern-learning ## Basic Information - **Project Name**: 设计模式学习 - **Description**: 学习设计模式实例化的的代码 - **Primary Language**: C++ - **License**: GPL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 3 - **Forks**: 0 - **Created**: 2020-11-30 - **Last Updated**: 2022-02-25 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 23种设计模式学习 ## 模板模式 - 方法思想 规定使用流程 使得原来需要早绑定的方法变成了晚绑定(程序启动时绑定->运行时绑定) 定义一个操作中算法的估价,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特性 - 具体解释 其实就是类似于C语言的回调,父类指定调用过程 在调用过程中有一部分的执行是固定的通用的,但是有部分是不通用的这个时候就需要将通用的部分指定好(稳定)不通用的部分则交给子类去实现 实现了程序启动时候的绑定到运行时的绑定。 - 实现方式 父类实现一个调用过程函数,其中有部分函数需要子类去实例化,最后子类调用父类的 过程函数,这样就实现了父类中需要子类实现的部分也在这个过程中调用到了。 [点击查看示例代码](https://gitee.com/csqs/design-pattern-learning/blob/master/%E6%A8%A1%E6%9D%BF%E6%A8%A1%E5%BC%8F.cpp) ## 策略模式 - 方法思想 有的时候使用的到解决方案有很多种,经常发生改变,如果直接将所有方法定义在解决的地方将会使得对象变得非常复杂,而且添加了一些不那么经常使用的解决方案也是一个性能上的负担,这个时候就需要实现一种方式即解决方案调用处**使用一个通用的方法,根据需要输出解决方案的不一样而产生不一样的结果**。 - 具体解释 根据不一样的输入,使用同一个操作接口,然后输出不一样的结果,这样在解决问题处只需要一个函数就可以,这里也处于稳定态,同样也不容易出错。 - 实现方式 实现一个抽象的基类定义一个通用的操作接口,继承这个类实现各种解决方法在使用的时候实例化子类即可实现。 [点击查看示例代码](https://gitee.com/csqs/design-pattern-learning/blob/master/%E7%AD%96%E7%95%A5%E8%80%85%E6%A8%A1%E5%BC%8F.cpp) ## 观察者模式 - 方法思想 在软件构造过程中,需要为某些对象**建立一种通知依赖关系**,一个对象(目标对象)的状态发送改变的时候所有依赖对象(观察者对象)都将得到通知,如果这样的依赖关系过于紧密,将使软件不能很好的抵御变化,将这种依赖关系弱化,并形成一种稳定的依赖关系,从而实现软件体系结构的松耦合 - 具体解释 其实观察者模式实现方式和策略模式差不多,都是让变化在子类中实现,策略模式是首先定义一个操作方式然后子类实现这个操作模式,观察者模式则是在发生变化的时候采用通知的方式来通知到绑定的子类。 - 实现方式 实现一个通知的时候调用的函数,然后创建一个列表,如果当前对象需要接收到通知则添加到列表中来 [点击查看示例代码](https://gitee.com/csqs/design-pattern-learning/blob/master/%E8%A7%82%E5%AF%9F%E8%80%85%E6%A8%A1%E5%BC%8F.cpp) ## 装饰模式 - 方法思想 在软件设计中如果责任划分不是那么的清晰,使用继承来实现的方式,随着需求的变化,子类会出现急剧的膨胀,同时会有大量的重复代码,这个时候就需要有一种好的方式来划分职责 - 具体解释 装饰模式是一种将模块功能细分的来实现在不同的子类都实现关于自己的部分代码,保持单一职责,在使用到其他额外操作的时候则通过基类指针调用额外操作的子类。 - 实现方式 首先必然要实现一个操作的基类,然后定义一个装饰类,继承基类,之后有扩展的需要使用到额外操作的继承这个装饰类,实现功能,需要用到基本操作(固定操作或者其他的一些操作)继承操作的基类,然后在创配的时候赋值即可 [点击查看示例代码](https://gitee.com/csqs/design-pattern-learning/blob/master/%E8%A3%85%E9%A5%B0%E6%A8%A1%E5%BC%8F.cpp) ## 桥模式 - 方法思想 桥模式使用对象之间的组合关系,结构了抽象和实现之间固定的绑定关系使得抽象和实现跨越沿着各自纬度来变化。即子类化 - 具体解释 在实现一些功能的时候我们需要实现的一些功能(业务和功能)我们可以通过再次细分使得每个类完成属于自己的那部分功能,即每个子类都需要父类里面的函数却不会出现大量代码重复,然后我们将其功能类的父类指针放在业务类里面的父类中,通过基类指针的方式调用不同的业务方式,实现组合替代继承减少了代码重复。 - 实现方式 首先定义两个类分别表示功能操作和业务操作(或者其他的一些组合)然后其中一个需要用到另一个类的函数里面,声明一个他的基类指针,子类继承以后直接使用基类指针来实现多态调用。 [点击查看示例代码](https://gitee.com/csqs/design-pattern-learning/blob/master/%E6%A1%A5%E6%A8%A1%E5%BC%8F.cpp) ## 工厂模式 - 方法思想 在软件系统中经常面临创建对象的工作,由于需求的变化,需要在创建的对象的具体类型经常变化。工厂模式就是来应对这种变化的 - 具体解释 在实际使用中,有的时候我们可能需要切换一个类来实现这个业务,比如 有业务A 和业务B 分别用class A class B 来实现在使用的过程中自然是希望能直接获取A 或者是B 工厂模式就是一个解决这个问题的方式,将AB 两个对象都创建咋工厂中,在使用的时候根据规则获取A 或者B 即可。 - 实现方式 定义一个抽象基类 A 和 B 都继承与他,定义一个获取规则 比如 输入1 表示获取A 输入2 表示获取2 然后返回基类对象,即可。 [点击查看示例代码](https://gitee.com/csqs/design-pattern-learning/blob/master/%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8F.cpp) ## 抽象工厂 - 方法思想 在软件系统中,经常面临一系列相互依赖的对象的创建工作,同时由于需求的变化,往往存在更多的创建工作,同时由于需求的变化,往往存在更多系列对象的创建工作。 - 具体解释 在实际需求中可能一个一个工厂无法满足使用需求,这个时候可能需要多个工厂,来满足某个场景,但是这样非常容易出现错误,于是乎我们需要将工厂整合在一起成为一个工厂,这就是抽象工厂。 - 实现方式 抽象工厂需要定义一个 工厂类,然后的定义一个抽象工厂类, 实例继承抽象工厂,实现工厂类,然后创建一个生成类,选择实际工厂。 [点击查看示例代码](https://gitee.com/csqs/design-pattern-learning/blob/master/%E6%8A%BD%E8%B1%A1%E5%B7%A5%E5%8E%82.cpp) ## 原型模式 - 使用场景 在软件系统中经常面临着"某些结构复杂的对象"的创建工作,由于需求的变化,这些对象经常面临剧烈的变化,但是却又比较稳定移植的接口。如何面对这种变化?如何向客户程序隔离出这些易变对象从而使得依赖这些易变对象的客户程序不随着需求的改变而改变 - 具体解释 有可能某个方式存在多个解决方案,我们通过设置一个原型然后,每次拷贝原型,进行处理,然后获取到结果,释放掉拷贝到的原型放弃中间处理数据这样在处理的时候无需关系创建过程,只需要管结果或者使用的中间数据,对比 策略模式是多个中间数据可以处理的。要注意的是每次都需要进行拷贝不然会修改掉原型,这样就会出现问题。 - 实现方式 实现一个原型基类,继承这样原型类实现各自的处理,最后使用的地方放一个 创建一个处理类,然后在使用的时候返回处理类的拷贝对象。 [点击查看示例代码](https://gitee.com/csqs/design-pattern-learning/blob/9ef5f0d1ed96808c5e56c9f118153752e58dc751/%E5%8E%9F%E5%9E%8B%E6%A8%A1%E5%BC%8F.cpp) ## 构建器 - 使用场景 在软件系统中,有的时候那里一个复杂对象的创建工作,其通常由各个部分的子对象用一定的算法构成,由于需求的变化,这个复杂算法的各个部分经常面临着剧烈的变化,但是将他们组合在一起的算法却是相对稳定的。如何提供一种封装机制来隔离出复杂对象的各个部分的变化,从而保持系统稳定攻坚算法不随着需求的改变而改变? - 具体解释 在对象创建的时候有的时候可能会传递多个参数来构造不同的对象,或者是构建方式一样构建的结果不一样的,这个时候我们可以抽出构建方法,然后分别实现操作来应对这种变化。 - 实现方式 实现一个抽象基类定义构建时调用的方法,然后定义一个管理类类似于桥模式,然后定义一个实现抽象基类的构建类,实例化构建过程。赋值给管理类。即可 [点击查看示例代码](https://gitee.com/csqs/design-pattern-learning/blob/9ef5f0d1ed96808c5e56c9f118153752e58dc751/%E6%9E%84%E5%BB%BA%E5%99%A8.cpp) ## 单例模式 - 使用场景 在软件系统中,经常有这样一些特殊的类,必须保证咋系统中只存在一个实例,才能确保他们逻辑的正确性、以及良好的效率,如果实现一种保证一个类只有一个实例? - 具体解释 在使用中有的时候某个类只允许有一个实例,但是很多地方要使用到这个类,所以要保证每次使用都不是重新创建出来的,这便是单例模式 - 实现方式 单例模式的实现方式非常的多,无非就是保证只会创建一次,具体可以查看示例代码。 [点击查看示例代码](https://gitee.com/csqs/design-pattern-learning/blob/9ef5f0d1ed96808c5e56c9f118153752e58dc751/%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F.cpp) ## 享元模式 - 使用场景 在软件系统采用存粹的对象方案的问题在于大量细粒度的对象会很快充斥在系统中,从而带来很高的运行时代价。如何避免大量细粒度对象问题的同事让外部客户程序能依然能够透明的使用面向对象的方式进行操作 - 具体解释 在对象使用非常频繁的情况下,重复的开辟和释放会消耗太长的时间,为此我们可以将创建的对象缓存下来,在使用的时候直接读取,节约开辟和释放的时间,来实现快速创建使用,而且对于用户而言跟重新创建是是差不多的效果。 - 实现方式 创建一个操作类, 然后使用工厂包装,创建过的对象加入对象池即可。 [点击查看示例代码](https://gitee.com/csqs/design-pattern-learning/blob/master/%E4%BA%AB%E5%85%83%E6%A8%A1%E5%BC%8F.cpp) ## 门面模式 - 使用场景 在组件的构建过程中,某些接口之间直接依赖常常会带来很多问题,甚至根本无法实现,采用添加一层间接的接口,来隔离本来互相紧密管理的接口是一种常用的解决方案。 - 具体解释 在软件系统设计中,无法避免的是接口之间的相互依赖,这样整体将会紧密的连接起来,如果出现变化,那么整个系统都会出现巨大的震动,为此我们可以通过实现一个中间件的方式隔离各自的变化,使得模块内部变化也不会影响到外部。 - 实现方式 这是一种抽象的软件思想,没有具体的实现方式,这里演示一个样例,用于展示这个思想 [点击查看示例代码](https://gitee.com/csqs/design-pattern-learning/blob/master/%E9%97%A8%E9%9D%A2%E6%A8%A1%E5%BC%8F.cpp) ## 代理模式 - 使用场景 在面向对象系统中,有些对象由于受到某种原因(比如对象的开销很大,或者某些操作需要安全控制,或者需要进程外的访问等)直接访问会给使用者、或者系统结构带来很多麻烦 - 具体解释 在实际使用的时候往往一个对象要实现的功能是非常复杂的 如果在一个类里面实现整个对象非常的庞大,且不好管理。对此可以使用使用一个代理类然后中间调用委托类的方式来实现高效,职责清晰的一个对象。 - 实现方式 [点击查看示例代码](https://gitee.com/csqs/design-pattern-learning/blob/master/%E4%BB%A3%E7%90%86%E6%A8%A1%E5%BC%8F.cpp) ## 适配器 - 使用场景 在软件系统中由于应用环境的变化,尝尝需要将一些现存的对象放在新的环境中应用,但是新环境要要求的接口是这些现存对象所不满足的。如何面对这种迁移的变化 - 具体解释 在使用环境中,尝尝出现某个操作已经定义好了,但是因为和现有业务逻辑有部分不匹配,为了能重用之前已经写好的代码,需要有一种开发的方式能重新定义一部分的操作,在界面程序开发中经常的用到,比如Android的listView 通过设置一个适配器的方式来修改显示数据。 - 实现方式 [点击查看示例代码](https://gitee.com/csqs/design-pattern-learning/blob/master/%E9%80%82%E9%85%8D%E5%99%A8%E6%A8%A1%E5%BC%8F.cpp) ## 中介者 - 使用场景 在构建系统过程中,经常会出现多个对象互相关联交互的情况,对象之间常常会维持一种复杂的引用关系,如果遇到一些需求更改,这种直接的引用关系将会面临不断地变化。 - 具体解释 中介者模式主要是解决多个对象双向绑定的解耦合作用,使用一个中介来实现各个类只和中间类进行双向绑定,然后由中介来实现消息的转发。 - 实现方式 [点击查看示例代码](https://gitee.com/csqs/design-pattern-learning/blob/master/%E4%B8%AD%E4%BB%8B%E8%80%85%E6%A8%A1%E5%BC%8F.cpp) ## 状态模式 - 使用场景 在组件构建过程中,某些对象的状态经常面临变化,如何对这些变化进行有效的管理?同时又维护高层模块的稳定。 - 具体解释 在我看来状态模式就是一个对象化了的状态机,在确定状态切换,或者说是确定步骤的时候非常适合用这种模式,能比较好的面对变化。 - 实现方式 [点击查看示例代码](https://gitee.com/csqs/design-pattern-learning/blob/master/%E7%8A%B6%E6%80%81%E6%A8%A1%E5%BC%8F.cpp) ## 备忘录 - 使用场景 在软件构建过程,默写对象的状态在转换过程中,可能由于某种需要,要求程序能够回溯到对象之前的处于某个点时的状态,如果使用一些共有接口来让其他对象得到对象的状态,便会暴露对象实现细节,如何实现对象状态良好保存与恢复,但同时又不会因此而破坏对象本身的封装性。 - 具体解释 保留一个类的某一时刻的状态,然后对类进行操作,之后可以恢复状态到之前保留的状态。 - 实现方式 [点击查看示例代码](https://gitee.com/csqs/design-pattern-learning/blob/master/%E5%A4%87%E5%BF%98%E5%BD%95%E6%A8%A1%E5%BC%8F.cpp) ## 组合模式 - 使用场景 在软件某些情况下,客户代码过多的依赖对于对象容器复杂的内部实现结构,对象容器内部实现结构的变化将会引起客户代码的频繁变化,带来代码的维护性,扩展性等弊端。如何实现将客户代码与复杂结构对象容器结构解耦,让对象容器自己来实现自身的复杂结构,从而使得客户代码就像处理肩带对象一样处理复杂的对象容器 - 具体解释 这样,在组合模式中,整个树形结构中的对象都属于同一种类型,带来的好处就是用户不需要辨别是树枝节点还是叶子节点,可以直接进行操作,给用户的使用带来极大的便利。 - 实现方式 [点击查看示例代码](https://gitee.com/csqs/design-pattern-learning/blob/master/%E7%BB%84%E5%90%88%E6%A8%A1%E5%BC%8F.cpp) ## 迭代器模式 - 使用场景 在软件构建过程中,集合对象内部结构常常变化各异,但对于这些集合对象,我们希望在不暴露其内部结构的同时,可以让外部客户代码透明的访问其中包含的元素。 - 具体解释 实际上还是通过一个中间层来隔离具体实现和取得元素之间的联系。 - 实现方式 [点击查看示例代码](https://gitee.com/csqs/design-pattern-learning/blob/master/%E8%BF%AD%E4%BB%A3%E5%99%A8%E6%A8%A1%E5%BC%8F.cpp) ## 职责链模式 - 使用场景 在软件构建过程中,一个请求可能被多个对象处理,但是每个请求在运行时只能有一个接受者,如果显式指定,将必不可少的带来请求发送者与接受者的紧耦合。如何使得请求的发送者不需要指定具体的接受者,让请求的接受者自己在运行时决定处理请求,从而使两者解耦。 - 具体解释 对象中有些操作在触发的时候,对象可以选择是否要处理这个操作,如果不处理就继续传递到下一个可以处理这个操作的对象,如果当前对象需要处理这个操作这样就直接处理。 - 实现方式 [点击查看示例代码](https://gitee.com/csqs/design-pattern-learning/blob/master/%E8%81%8C%E8%B4%A3%E9%93%BE%E6%A8%A1%E5%BC%8F.cpp) ## 命令模式 - 使用场景 在软件构建过程中,行为请求者与行为实现者通常呈现一种紧耦合,但是在默写场合,需要对行为进行记录、撤销等事务等处理的时候,如何将行为请求者,与行为实现者解耦。将一组行为抽象为对象,这样就实现了二者之间的松耦合 - 具体解释 这是一个和代理模式非常相似的模式,这个都是功能各自使用一个类来去实现,然后传递到使用的类里面来实现各自的类实现各自的功能,代理模式注重与子功能也就是对于业务的具体操作分开实现,命令模式则是一个完全独自化的功能。 - 实现方式 [点击查看示例代码](https://gitee.com/csqs/design-pattern-learning/blob/master/%E5%91%BD%E4%BB%A4%E6%A8%A1%E5%BC%8F.cpp) ## 访问器模式 - 使用场景 在软件构建过程中,由于需求的改变,某些类层次结构中尝尝需要增加新的行为,如果直接在基类中做这样的更改,将会给子类带来很繁重的变更负担,甚至破坏原有设计。在不更改类层次结构的前提下,在运行时根据需要透明的为类层次结构上的各个类动态添加新的操作,从而避免出现这些问题。 - 具体解释 在使用过程中,有些需求可能导致基类变化,这样整个结构都需要发生改变,于是需要通过一种方式来实现增加新的内容不影响原先已经实现的方式。 - 实现方式 [点击查看示例代码](https://gitee.com/csqs/design-pattern-learning/blob/master/%E8%AE%BF%E9%97%AE%E5%99%A8%E6%A8%A1%E5%BC%8F.cpp) ## 解析器 - 使用场景 在软件攻坚过程中,如果某一特定淋雨的问题比较复杂,类似的结构不断重复出现,如果使用普通的编程方式来实现将要面临的非常频繁变化,这样可以将特定领域的问题表达为某种语法规则下的句子然后构建一个解释器来解释这样的句子,从而解决问题的目的 - 具体解释 给定一个语言,定义他的文法的一种表示,并定义一种解释器,这个解释器使用该表示来解释语言中的句子 - 实现方式 [点击查看示例代码](https://gitee.com/csqs/design-pattern-learning/blob/master/%E8%A7%A3%E6%9E%90%E5%99%A8.cpp)