目录
1、软件设计模式的起源
2、什么是设计模式?
2.1、设计模式的设计意图
2.2、设计模式的分类准则
3、为什么要学习设计模式
4、如何学习设计模式
5、最后
VC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)https://blog.csdn.net/chenlycly/article/details/124272585C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)https://blog.csdn.net/chenlycly/article/details/125529931C++软件分析工具案例集锦(正在更新中...)https://blog.csdn.net/chenlycly/category_12279968.html 大家在写代码或阅读代码时,会或多或少地用到或接触到设计模式,设计模式可以从设计的角度帮我们高效地解决某些业务场景下的复杂问题。今天就来聊一下设计模式相关的概述性的内容。
1、软件设计模式的起源
说到设计模式的起源,就必须要提到一本设计模式经典书籍以及这本书的GOF四人组作者。在上个世纪90年代,准确地说是1995年,由Erich Gamma、Richard Helm、RalphJohnson和John Vlissides合著的《Design Patterns :Elements ofReusable Object-Oriented Software(设计模式:可复用面向对象软件的基础)》一书的出版,正式拉开了软件设计模式的序幕。
这四位作者常被称为“四人组(Gang of Four, GoF)”,而这本书也就被称为“四人组(或GoF) ”书,所以大家说的设计模式,也被称为GOF设计模式。他们首次总结出一套在软件开发中可以反复使用的经验,帮助我们提高代码的可重用性、系统的可维护性等,帮我们解决软件开发中遇到的复杂问题。这些总结出来的软件设计经验,就是我们讲的软件设计模式,其设计思想适用于多个开发语言。
2、什么是设计模式?
在软件开发中,经过验证的,用于解决在特定环境下,重复出现的、特定问题的解决方案,这些解决方案就是设计模式。模式就是解决问题的经验和套路,设计模式(Design pattern)就是一套经过前人反复使用,总结出来的程序设计经验。当然,设计模式并不是软件行业特有的,其实很多行业都有自己的设计模式。
设计模式总共分为三大类:
- 第一类是创建型模式 ,该模式通常和对象的创建有关,涉及到对象实例化的方式。包括:单例模式、工厂模式、抽象工厂模式、建造者模式、原型模式五种;
- 第二类是结构型模式,结构型模式描述的是如何组合类和对象来获得更大的结构。包括:代理模式、装饰者模式、适配器模式、桥接模式、组合模式、外观模式、享元模式共7种模式。
- 第三种是行为型模式,用来描述对类或对象怎样交互和怎样分配职责。共有:模板模式、命令模式、责任链模式、策略模式、中介者模式、观察者模式、备忘录模式、访问者模式、状态模式、解释器模式、迭代器模式11种模式。
2.1、设计模式的设计意图
23种设计模式都是针对不同的设计应用场景,都有对应的设计意图,如下:
Abstract Factory(抽象工厂模式) | 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。 |
Adapter(适配器模式) | 将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。 |
Bridge(桥接模式) | 将抽象部分与它的实现部分分离,使它们都可以独立地变化。 |
Builder(建造者模式) | 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。 |
Chain of Responsibility(责任链模式) | 为解除请求的发送者和接受者之间耦合,而使多个对象都有机会处理这个请求。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它。 |
Command(命令模式) | 将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可取消的操作。 |
Composite(组合模式) | 将对象组合成树形结构以表示“部分-整体”的层次结果。Composite使得客户对单个对象和符合对象的使用具有一致性。 |
Decorator(装饰者模式) | 动态地给一个对象添加一些额外的职责。就扩展功能而言,Decorator模式比生成子类方式更为灵活。 |
Facade(外观模式) | 为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。 |
Factory Method(工厂模式) | 定义一个用于创建对象的接口,让子类决定将哪一个类实例化。Factory Method 使一个类的实例化延迟到其子类。 |
Flyweight(享元模式) | 运用共享技术有效地支持大量细粒度的对象 |
Interpreter(解释器模式) | 给定一个语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。 |
Iterator(迭代器模式) | 提供一种方法顺序访问一个聚合对象中的各个元素,而又不需暴露该对象的内部表示。 |
Mediator(中介者模式) | 用一个中介对象来封装一系列的对象交互。中介者使个对象不需要显示地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。 |
Memento(备忘录模式) | 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到保存的状态。 |
Observer(观察者模式) | 定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动刷新。 |
Prototype(原型模式) | 用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象。 |
Proxy(代理模式) | 为其他对象提供一个代理以控制对这个对象的访问。 |
Singleton(单例模式) | 保证一个类仅有一个实例,并提供一个访问它的全局访问点。 |
State(状态模式) | 允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它所属的类。 |
Strategy(策略模式) | 定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换本模式使得算法的变化可独立于使用它的客户。 |
Template Method(模版模式) | 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。Template Method使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 |
Visitor(访问者模式) | 表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。 |
2.2、设计模式的分类准则
设计模式分类依据两条准则,23种设计模式的归类如下图所示:
目的 | ||||
创建型 | 结构型 | 行为型 | ||
范围 | 类 | Factory Method(工厂模式) | Adapter(适配器模式) | InterPreter(解释器模式) Template Method(模版模式) |
对象 | Abstract Factory(抽象工厂模式) Builder(建造者模式) Prototype(原型模式) Singleton(单例模式) | Adapter(适配器模式) Bridge(桥接模式) Composite(组合模式) Decorator(装饰者模式) Facade(外观模式) Flyweight(享元模式) Proxy(代理模式) | Chain of Responsibility(责任链模式) Command(命令模式) Iterator(迭代器模式) Mediator(中介者模式) Memento(备忘录模式) Observer(观察者模式) State(状态模式) Strategy(策略模式) Visitor(访问者模式) |
第一是目的准则,即模式是用来完成什么工作的。模式依据其目的可分为创建型、结构型、行为型三种。创建型模式与对象的创建有关;结构型模式处理类或对象的组合;行为型模式对类或对象怎样交互和怎样分配职责进行描述。
第二是范围准则,指定模式主要是用于类还是用于对象。类模式处理类和子类之间的关系,这些关系通过继承建立,是静态的,在编译时刻便确定了下来。对象模式处理对象间的关系,这些关系在运行时刻是可以变化的,更具动态性。从某种意义上来说,几乎所有模式都使用继承机制,所以“类模式”只指那些集中于处理类间关系的模式,而大部分模式都属于对象模式的范畴。
创建型类模式将对象的部分创建工作延迟到子类,而创建型对象模式则将它延迟到另一个对象中。结构性类模式使用继承机制来组合类,而结构型对象模式则描述了对象的组装方式。行为型类模式使用继承描述算法和控制流,而行为型对象模式则描述一组对象怎样协作完成单个对象所无法完成的任务。
还有其他组织模式的方式。有些模式经常会被绑在一起使用,例如,Composite常和Iterator或Visitor一起使用;有些模式是可替代的,例如Prototype常用来替代Abstract Factory;有些模式尽管使用意图不同,但产生的涉及结果是很相似的,例如,Composite和Decorator的结构图是相似的。
3、为什么要学习设计模式
设计模式是很多前辈经验的积累,是一些典型问题的优秀解决方案。学习设计模式,可以学到前辈们的经验,领会和吸收他们的设计思路,掌握他们解决问题的方法,有效地提升个人技术能力。
1)从宏观的代码视角看
使用设计模式,可以摒弃一些重复冗繁的操作,写出优雅的代码。使用设计模式,可以更好地重构代码。平时我们写的代码虽然满足了需求,但现有代码可能不方便后期扩展和维护,需要对代码进行重构。很多框架和开源代码可维护性与可扩展性比较好,都在大量使用设计模式。
2)从微观的工作学习视角看
大家在日常软件项目开发过程中会或多或少地使用到一些设计模式,比如单例模式、简单工厂模式、观察者模式等。在笔试面试时,可能也会被问到设计模式相关的内容,比如你用过那些设计模式,能不能手写某个设计模式的实现代码等。此外,我们在阅读和学习开源代码时,开源代码中也会大量地使用设计模式。所以学习设计模式是很有必要的,不仅工作中会用到,笔试面试时也可能会涉及到!
比如我们在IM即时通讯(聊天)软件中,屏幕截图功能已经是标配的功能,需要支持矩形、椭圆、箭头、曲线等图元的绘制,这里使用简单工厂模式实现比较恰当,在基类CShape中定义用于图元绘制的纯虚接口Draw,然后在继承于基类CShape的CRectangle(矩形类)、CEllipse(椭圆类)、CCurve(曲线类)、CLine(箭头类)等子类中去实现具体图元绘制的接口,我们只需要给这些子类设置坐标等数据就可以了。相关类图如下所示:
4、如何学习设计模式
我们要从思想上和方法上吸收设计模式的精髓,将之融入到我们的设计思路中,在进行软件的分析和设计时,能很好的使用这写设计思想去解决问题。
要真正理解和掌握诸多设计模式,必须要和软件设计实践有效地结合起来,看完后思考,思考后应用,然后再看、再思考、再应用,这是个循环往复的过程。
学习设计模式的大致流程如下:
- 1)准确理解每个设计模式的功能、基本结构和标准实现,了解它们的使用场景与使用效果。
- 2)在实际的软件开发中,尝试着使用这些设计模式,并反复思考这些设计模式是否适用,是否需要做一些改变。
- 3)有了实际的模式应用经验,再回头去看设计模式的理论,会有不同的感悟和收获,一边看一边结合着应用去思考。比如设计模式的本质是什么?是如何实现的?如何和具体的应用场景结合起来的?这个设计模式的出发点是什么?等等。
- 4)在实际开中结合理论思考,然后再应用,再思考...如此循环,反复使用,直到能有效地掌握这些设计模式。
总之,在使用设计模式时要理论与实践相结合,理论指导实践,实践反过来加深对理论的理解与认知,如此循环往复,成螺旋式上升。
5、最后
《重构与模式》一书中有一句经典的话:如果想成为一名更优秀的软件设计师,了解优秀软件设计的演变过程比学习优秀设计本身更有价值,因为设计的演变过程中蕴藏着大智慧!
23种设计模式能让你感知到“封装变化、“对象间的松散耦合”、“针对接口编程”的思维,从而设计出易维护、易扩展、易复用、灵活性好的代码。
此外,大部分设计模式的教材都是使用Java语言来讲解的,很多C++开发人员可能对Java语言不了解,学习起来可能会有些别扭。后续文章中详细讲解的23个设计模式,均采用C++代码实现,方便广大C++开发人员查阅!