C++常⽤的11种设计模式
这⾥写⽬录标题
⼯⼚模式
定义:将⼯⼚变成⼀个抽象类,在⾥⾯定义⼀个纯虚函数,具体⽣成什么产品交给⼦类继承去决定(抽象产品类-》具体产品类-》抽象⼯⼚类-》具体⼯⼚类)
*
作⽤:封装对象的创建,解决new解耦的问题
*
适⽤场景:⽤来⽣产同⼀等级结构中的固定产品。(⽀持增加任意产品)
*
实例:⽔果例⼦;数据库访问;
*
优点:当系统扩展需要添加新的产品对象时,仅仅需要添加⼀个具体对象以及⼀个具体⼯⼚对象,原有⼯⼚对象不需要进⾏任何修改,符合开闭原则。
*
缺点:每增加⼀个产品就要增加⼀个产品⼯⼚的类,增加了额外的开发量。
单例模式(懒汉式、饿汉式)
定义:⼀个单例类只创建⾃⼰的唯⼀实例对象,有且只有⼀个,这个单例类提供了⼀种访问其唯⼀实例的对象的⽅式,可以直接访问,不需要实例化该类的对象。
*
作⽤:在整个程序空间中,该类只存在⼀个实例对象。
*
实现步骤:1、构造函数私有化。2、提供⼀个全局的静态⽅法(全局访问点)。3、在类中定义⼀个静态指针,指向本类的静态变量指针。*
适⽤场景:创建的⼀个对象需要消耗的资源过多,⽐如I/O⾬数据库的连接。
*
实例:1、每部苹果⼿机都有⾃⼰的唯⼀序列号。2、⼀个班级只有⼀个班主任。3、Windows 是多进程多线程的,在操作⼀个⽂件的时候,就不可避免地出现多个进程或线程同时操作⼀个⽂件的现象,所以所有⽂件的处理必须通过唯⼀的实例来进⾏。4、 ⼀些设备管理器常常设计为单例模式,⽐如⼀个电脑有两台打印机,在输出的时候就要处理不能两台打印机打印同⼀个⽂件。
*
优点:1、在内存⾥只有⼀个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(⽐如页⾯缓存)。2、避免对资源的多重占⽤(⽐如⽂件的写操作)。
*
缺点:没有接⼝,不能继承,⼀个类只关⼼内部逻辑,⽽不关⼼外⾯怎么样来实例化。
适配器模式
定义:适配器模式是作为两个不兼容的接⼝之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独⽴接⼝的功能。这种模式涉及到⼀个单⼀的类,该类负责加⼊独⽴的或不兼容的接⼝功能。例如,读卡器是作为内存卡和笔记本之间的适配器。将内存卡插⼊读卡器,再将读卡器插⼊笔记本,这样就可以通过笔记本来读取内存卡。
其中适配器模式⼜分为类适配器和对象适配器
*
类适配器采⽤多继承实现,并提供适配后的接⼝;对象适配器是将需要适配的对象进⾏包装然后提供给适配后的接⼝。
*
适⽤场景:有动机的修改⼀个正常运⾏的系统的接⼝,这时应该考虑使⽤适配器模式。
*
实例:1、美国电器 110V,中国 220V,就要有⼀个适配器将 110V 转化为 220V。 2、JAVA JDK 1.1 提供了 Enumeration 接⼝,⽽在 1.2 中提供了 Iterator 接⼝,想要使⽤ 1.2 的 JDK,则要将以前系统
的 Enumeration 接⼝转化为 Iterator 接⼝,这时就需要适配器模式。 3、在 LINUX 上运⾏ WINDOWS 程序。 4、JAVA 中的 jdbc。
*
优点:1、可以让任何两个没有关联的类⼀起运⾏ 2、提⾼了类的复⽤ 3、增加了类的透明度 4、灵活性好
*
缺点:过多的使⽤适配器,会让系统显得很凌乱,不易整体把握。
外观模式
定义:提供了⼀个统⼀的接⼝,⽤来访问⼦系统的⼀接⼝。向现有的系统添加⼀个接⼝,⽤来隐藏系统的复杂性。
作⽤:简化类的接⼝,让⼀系列的复杂过程封装到内部,对外只提供最简单的接⼝。
适⽤场景:1、客户端不需要知道系统内部的复杂联系,,整个系统只需要提供⼀个“接待员”即可。2、定义系统的⼊⼝。3、为复杂的模块或⼦系统提供外界访问的模块。4、⼦系统相对独⽴。
实例:1、⾃⼰做⼤餐(很烦很复杂,过程多)VS到餐厅做⼤餐(接待员⼀键式安排,⾃⼰等着就好)2、去医院看病,可能要去挂号、门诊、划价、取药,让患者或患者家属觉得很复杂,如果有提供接待⼈员,只让接待⼈员来处理,就很⽅便。
优点:1、减少系统的相互依赖,所有的依赖都是对外观类的依赖,与⼦系统⽆关。2、对⽤户隐藏了⼦系统的具体实现,减少⽤户对⼦系统的耦合,这样就算具体的⼦系统发⽣了改变,⽤户也不会知道。3、提⾼安全性。
缺点:不符合开闭原则,如何业务变更,则需要修改外观类,继承重写都不合适。
代理模式
定义:为其它对象提供⼀种代理,以控制对这个对象的访问。⽤户操作代理,代理操作具体的类。
*
作⽤:所谓代理模式就是在⽤户和具体类之间加⼀个代理类,起到⼀个中介的作⽤。单例模式的几种实现方式
*
适⽤场景:1、远程代理。 2、虚拟代理。 3、Copy-on-Write 代理。 4、保护(Protect or Access)代理。 5、Cache代理。 6、防⽕墙(Firewall)代理。 7、同步化(Synchronization)代理。 8、智能引⽤(Smart Reference)代理。
*
实例:1、Windows⾥⾯快捷⽅式。2、猪⼋戒去⾼翠兰,结果⾼翠兰是孙悟空变得,这个孙悟空就是⾼翠兰的代理类,把⾼翠兰的外貌抽象出来,孙悟空和⾼翠兰都实现了这个接⼝,⽽猪⼋戒看不出来⾼翠兰其实是孙悟空变得。3、⽕车票不⼀定是在⽕车站买,也可以在代售点或者各种app上买。 4、⼀张⽀票或银⾏存单是账户中资⾦的代理。⽀票在市场交易中⽤来代替现⾦,并提供对签发⼈账号上资⾦的控制。5、卖书(书店和淘宝作为代理商,⽤户通过代理商买书)。 6、智能指针。7、Java⾥⾯的spring aop。
*
优点:1、代理模式能将代理对象与真实对象被调⽤的⽬标对象分离,降低了系统的耦合度,扩展性好,保护⽬标对象,增强⽬标对象
*
缺点:1、代理模式会造成系统设计中类的数⽬增加,增加了系统的复杂度,2、在客户端和⽬标对象之间增加⼀个代理对象会造成请求处理速度变慢。
*
包装模式(装饰器模式)
定义:以透明动态的⽅式来动态扩展对象的功能,也是继承关系的⼀种代替⽅案(合成复⽤原则:组合⼤于继承)。允许向⼀个现有的对象添加新的功能,同时⼜不改变其结构,是作为现有类的⼀个包装。
*
作⽤:在不想增加很多⼦类的情况下扩展。
*
适⽤场景:1、扩展⼀个类的功能。2、动态增加功能,动态撤销。
*
实例:1、开奶茶店 (需要加各种配料)2、⽼婆化妆(各种化妆品) 3、孙悟空有 72 变,当他变成"庙宇"后,他的根本还是⼀只猴⼦,但是他⼜有了庙宇的功能。 4、不论⼀幅画有没有画框都可以挂在墙上,但是通常都是有画框的,并且实际上是画框被挂在墙上。在挂在墙上之前,画可以被蒙上玻璃,装到框⼦⾥;这时画、玻璃和画框形成了⼀个物体。5、汽车功能(⾛、跑、飞、潜⽔。。。)
*
优点:1、饰器模式与继承关系的⽬的都是要扩展对象的功能,但是装饰器模式⽐继承提供更多的灵活性(动态选择)。2、通过使⽤不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同⾏为的组合(⼆维象限)。
*
缺点:装饰器模式会导致设计中出现很多⼩类,过度使⽤会使程序变得很复杂。
桥接模式
定义:将抽象部分与他的实现部分相分离,使他们都可以独⽴的变化。
作⽤:⼀维扩展⽤继承/组合,多维扩展⽤桥接。(实现系统可能有多个⾓度分类,每⼀种⾓度都可能
变化,那么把这种多⾓度分类给分离出来让他们独⽴变化,减少他们之间耦合。)(不是继承,⽽是关联)
*
抽象部分-》优化的抽象部分-》实现部分-》实现部分的具体实现
*
适⽤场景:1、⼀个类存在两个独⽴变化的维度,且这两个维度都需要进⾏扩展。2、对于那些不希望使⽤继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适⽤。
*
实例:1、电脑系统组装 2、家电各种电器与品牌的关系3、汽车品牌与发电机
*
优点:抽象与实现的分离、优秀的扩展能⼒、实现细节对⽤户透明
*
缺点: 1、桥接模式的引⼊会增加系统的理解与设计难度,由于聚合关联关系建⽴在抽象层,要求开发者针对抽象进⾏设计与编程。2、桥接模式要求正确识别出系统中两个独⽴变化的维度,因此其使⽤范围具有⼀定的局限性。
模板⽅法模式
定义:定义⼀个操作中的算法的⾻架,⽽将⼀些步骤延迟到⼦类中。
*
作⽤:模板⽅法使得⼦类可以不改变⼀个算法的结构即可重定义该算法的某些特定步骤
*
适⽤场景:1、⼀次性实现⼀个算法的不变部分,可变的部分交给⼦类去实现。2、各⼦类中的公共⾏为应被提取出来并集中到⼀个公共⽗类中以避免代码重复。3、需要通过⼦类来决定⽗类算法中某个步骤是否执⾏,实现⼦类对⽗类的反向控制。
*
实例:1、学⽣都需要去上课,其上课的具体流程是上课、听课、下课,但是不同类学⽣听课(上课、下课)的具体内容不同。2、在造房⼦的时候,地基、⾛线、⽔管都⼀样,只有在建筑的后期才有加壁橱加栅栏等差异。 3、西游记⾥⾯菩萨定好的 81 难,这就是⼀个顶层的逻辑⾻架。
*
优点:1、封装不变部分,扩展可变部分。2、提取公共代码,便于维护。3、⾏为由⽗类控制,⼦类实现。
*
缺点:每⼀个不同的实现都需要⼀个⼦类去实现,导致类的个数增加,使得系统更加庞⼤。
*
注意事项:⼀般模板⽅法都加上final关键字,防⽌恶意操作。
策略模式
定义:定义了⼀系列的算法,并将每⼀个算法封装起来,⽽且可以使他们可以相互替换。
*
作⽤:让算法独⽴于使⽤他们的客户⽽独⽴变化。(在有多种算法相似的情况下,使⽤if…else所带来的复杂和难以维护)。
*
适⽤场景:1、如果在⼀个系统⾥由很多类,⽽这些类之间的区别仅是⾏为不同,那就需要⽤策略模式来让对象动态的在许多⾏为中选择⼀个⾏为。2、⼀个系统需要动态的在⼏种算法中选择⼀种。3、如果⼀个对象有很多的⾏为,如果使⽤不恰当的模式,这些⾏为就只好使⽤多重的条件语句来实现。
*
实例:1、鸭⼦游戏 2、诸葛亮的锦囊妙计,每⼀个锦囊就是⼀个策略。3、旅⾏的出游⽅式,选择骑⾃⾏车、坐汽车,每⼀种旅⾏⽅式都是⼀个策略。
*
优点:1、算法可以⾃由切换 2、避免使⽤多重条件判断 3、扩展性好。
*
缺点:1、策略类会很多 2、所有策略类都需要对外暴露。
观察者模式
定义:定义对象间的⼀种⼀对多的依赖关系,当⼀个对象的状态发⽣改变时,所有依赖于它的对象都得到通知并⾃动更新。(触发联动)*
作⽤:⼀个对象状态改变给其它对象通知的问题,⽽考虑到易⽤和低耦合,保证⾼度的协作。
*
可以将观察者们放进⼀个容器⾥。
*
适⽤场景:1、⼀个抽象模型有两个⽅⾯,其中⼀个⽅⾯依赖于另⼀个⽅⾯,将这些⽅⾯封装在独⽴的对象中使他们可以各⾃独⽴的改变和复⽤。2、⼀个对象的改变将导致其它⼀个或者多个对象也发⽣改变,⽽不知道具体有多少对象将发⽣改变,可以降低对象之间的耦合度。
3、⼀个对象必须通知其他对象,⽽并不知道这些对象是谁。
4、需要在系统中创建⼀个触发链,A对象的⾏为将影响B对象,B对象的⾏为将影响C对象……,可以使⽤观察者模式创建⼀种链式触发机制。
*
实例:1、拍卖的时候,拍卖师观察最⾼拍价,然后通知给其它拍卖家。2、西游记⾥⾯悟空请求菩萨降服红孩⼉,菩萨洒了⼀地⽔招来⼀个⽼乌龟,这个乌龟就是观察者,他观察菩萨洒⽔这个动作。
*
优点:1、观察者和被观察者是抽象耦合的。2、建⽴⼀套触发机制。
*
缺点: 1、如果⼀个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。 2、如果在观察者和观察⽬标之间有循环依赖的话,观察⽬标会触发它们之间进⾏循环调⽤,可能导致系统崩溃。 3、观察者模式没有相应的机制让观察者知道所观察的⽬标对象是怎么发⽣变化的,⽽仅仅只是知道观察⽬标状态发⽣了变化。
责任链模式
定义:将所有请求的处理者通过前⼀对象记住下⼀个对象的引⽤⽽形成⼀条链,当有请求发⽣时,可以沿着这条链进⾏传递,知道有对象处理为⽌。
*
作⽤:客户只需要将请求发送到责任链上即可,⽆需关⼼请求的处理细节和请求的传递过程,所以责任链将请求的发送者和请求的处理者相耦合了。
*
适⽤场景:⼀个请求有多个处理对象(处理者可以动态配置、处理者的顺序可以动态配置、请求不需要指定具体的处理者)
*
实例:1、假如规定学⽣请假⼩于或等于 2 天,班主任可以批准;⼩于或等于 7 天,系主任可以批准;⼩于或等于 10 天,院长可以批准;其他情况不予批准。2、击⿎传花。
*
优点:1、降低耦合度,它将请求的发送者和请求的处理者解耦。2、简化了对象,使得对象不需要知道链的结构。3、增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。 4、增加新的请求处理类很⽅便。
*
缺点:1、执⾏未处理:不能保证请求⼀定会被接收到。2、执⾏路径长:系统性能将会受到⼀定影响,⽽且在进⾏调试代码时不太⽅便。
3、执⾏的死循环:建链不当导致环形链表,死循环。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。