C/C++ 知识点-设计模式总结(C++和Python实现)

目录

前言

创建型模式

工厂方法模式(Factory Method)

抽象工厂模式(Abstract Factory)

单例模式(Singleton)

建造者模式(Builder)

原型模式(Prototype)

结构型模式

代理模式(Proxy)

适配器模式(Adapter)

外观模式(Facade)

装饰模式(Decorator)

桥接模式(Bridge)

享元模式(Flyweight)

组合模式(Composite)

行为型模式

职责链模式(Chain of Responsibility)

策略模式(Strategy)

状态模式(State)

观察者模式(Observer)

迭代器模式(Iterator)

备忘录模式(Memento)

命令模式(Command)

模板方法模式(Template Method)

中介者模式(Mediator)

解释器模式(Interpreter)

访问者模式(Visitor)

对比总结


前言


GoF的23种设计模式,包括创建型、结构型和行为型,其涵盖了面向对象思想的精髓以及诸多细节。本文结合《设计模式》和《大话设计模式》,并用C++和Python实现了《大话设计模式》中的23种模式案例。
案例实现


创建型模式


工厂方法模式(Factory Method)

  1. 工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化哪个类。
  2. 工厂方法把简单工厂的内部判断逻辑移到了客户端代码,本来需要修改工厂类,现在是修改客户端。
  3. 简单工厂模式违背了开放-封闭原则,工厂方法模式借助多态,克服了该缺点,却保持了封装对象创建过程的优点。

抽象工厂模式(Abstract Factory)

  1. 抽象工厂模式:提供一个创建一系列相关或互相依赖对象的接口,只需要知道对象的系列,无需知道具体的对象。
  2. 在客户端中,具体工厂类只在初始化时出现一次,更改产品系列即可使用不同产品配置。
  3. 利用简单工厂类替换抽象工厂类及其子类,可以使客户端不再受不同系列的影响。
    结合反射机制,Assembly.Load(“程序集名称”).CreateInstance(“命名空间”.“类名”),可以直接通过字符串创建对应类的实例。所有在简单工厂中,都可以通过反射去除switch或if,解除分支判断带来的耦合。
  4. 反射中使用的字符串可以通过配置文件传入,避免更改代码。

单例模式(Singleton)

  1. 单例模式:让类自身保证它只有一个实例,并提供一个全局访问点。
  2. 多线程下单例模式可能失效,需要采取双重锁定的的方式,确保被锁定的代码同一时刻只被一个进程访问。
  3. 饿汉式单例:即静态初始化方式,在类初始化时产生私有单例对象,会提前占用资源;渴汉式单例:在第一次被引用时将自己初始化,会产生多线程访问安全问题,需要添加双重锁定。

建造者模式(Builder)

  1. 建造者模式:将复杂对象的创建与表示分开,使得相同的创建过程可以有不同的表示。用户只需制定需要建造的类型,不需要知道建造的过程和细节。
  2. 指挥者是建造者模式中重要的类,用于控制建造过程,也可以隔离用户与建造过程的关联。
  3. 建造者隐藏了产品的组装细节,若需要改变一个产品的内部表示,可以再定义一个具体的建造者。
  4. 建造者模式是在当前创造复杂对象的算法,独立于该对象的组成部分和装配方式时适用的模式。

原型模式(Prototype)

  1. 原型模式:用原型实例指定创建对象的种类,并通过拷贝这些原型创建对象。本质是从一个对象再创建另一个可定制的对象,并且不需要知道创建细节。
  2. 原型抽象类的关键是有一个Clone()方法,原型具体类中复写Clone()创建当前对象的浅表副本。
  3. 对.Net而言,由于拷贝太常用原型抽象类并不需要,在System命名空间中提供了ICloneable接口,其中唯一的方法就是Clone(),只要实现这个接口就可以完成原型模式。
  4. 原型拷贝无需重新初始化对象,动态获取对象的运行状态。既隐藏了对象创建的细节,又提升性能。
  5. 在具体原型类中,MemberwiseClone()方法是浅拷贝,对值类型字段诸位拷贝,对引用类型只复制引用但不会把具体的对象值拷贝过来。
  6. 比起浅拷贝,深拷贝把引用对象的变量指向新对象,而不是原被引用的对象。对于需要深拷贝的每一层,都需要实现ICloneable原型模式。
  7. 数据集对象DataSet,Clone()是浅拷贝,Copy()是深拷贝。

结构型模式


代理模式(Proxy)

  1. 代理模式:为其他对象提供一种代理以控制对这个对象的访问。实际上是在访问对象时引入一定程度的间接性。
  2. 远程代理:为一个对象在不同地址空间提供局部代表,隐藏一个对象存在于不同空间的事实。如.Net加入Web引用,引入WebService,此时项目会生成WebReference的文件夹,就是代理。
  3. 虚拟代理:根据需要创建开销很大的对象,通过它存放实例化需很长时间的真实对象。HTML中的多图,就是通过虚拟代理代替了真实图片,存储路径和尺寸。
  4. 安全代理:控制真实对象的访问权限,用于对象应该拥有不同的访问权限时。
  5. 智能指引:当调用真实对象时,代理处理一些另外的事情。通过代理在访问对象时增加一些内务处理。

适配器模式(Adapter)

  1. 适配器模式:当系统数据和行为都一致,只有接口不符合时,将一个类的接口转化为客户端期望的另一个接口。
  2. 适配器模式用于服用一些现存的类,常用在第三方接口或软件开发后期双方都不易修改的时候。
  3. 在.Net中DataAdapter是用于DataSet和数据源间的适配器,Fill更改DataSet适配数据源,Update更改数据源适配DataSet。

外观模式(Facade)

  1. 外观模式:为子系统中一组接口提供一个一致的界面,即定义一个高层接口,增加子系统的易用性。
  2. 外观模式完美体现了依赖倒转原则和迪米特法则。
  3. 设计初期阶段,在MVC三层架构中,任意两层间建立外观Facade。
  4. 子系统会因不断演化变得复杂,增加外观Facade提供简单简单接口减少依赖。
  5. 在维护一个大的遗留系统时,新的开发又必须依赖其部分功能。此时,开发一个外观Facade类,从老系统中抽象出比较清晰的简单接口。让新系统只与Facade交互,而Facade与遗留代码交互所有的工作。

装饰模式(Decorator)

  1. 装饰模式:动态的给一个对象添加一些额外的职能,把所需功能按顺序串联起来并进行控制。
  2. 每个要装饰的功能放在单独的类中,并让这个类包装它所要修饰的对象。当需要执行特殊行为时,客户端就可以根据需要有选择的、有顺序的使用装饰功能包装对象了。
  3. 装饰模式有效的把类的核心职能和装饰功能区分开了,并且可以去除相关类中重复的装饰逻辑。

桥接模式(Bridge)

  1. 对象的继承关系编译时已确定,所以无法在运行时修改从父类继承的实现。由于紧耦合,父类中任何的改变必然会导致子类发生变化。当需要复用子类,但继承下来的方法不合适时,必须重写父类或用其他类替代。这种依赖性限制了灵活性和复用性。
  2. 合成/聚合复用原则:尽量使用合成和聚合而不是继承。可以保证每个类封装集中在单个任务上,不会出现规模太大的类及继承结构。
  3. 桥接模式:抽象类和其派生类分离,各自实现自己的对象。若系统可以从多角度分类,且每种分类都可能变化,则把多角度分离独立出来,降低耦合。

享元模式(Flyweight)

  1. 享元模式:运用共享技术有效支持大量细粒度对象。
  2. 在享元模式对象内部不随环境改变的共享部分是内部状态,不可共享需要通过调用传递进来的参数是外部状态。
  3. 使用享元模式的场景包括,一个应用程序产生了大量的实例对象,占用了大量内存开销;或对象的大多数状态为外部状态,删除内部状态后可以用较少的共享对象来取代组对象。
  4. 应用场景有正则表达式、浏览器、机器人指令集等。

组合模式(Composite)

  1. 组合模式:将对象的组合以树形的层次结构表示,对单个对象和组合结构的操作具有一致性。
  2. 透明方法:叶子和分枝对外接口无差别;安全方法:分枝具有添加删除叶子的接口,低层抽象接口和叶子没有。
  3. 基本对象组合成组合,组合又可以被组合,不断递归下去,在任何用到基本对象的地方都可以使用组合对象。

行为型模式


职责链模式(Chain of Responsibility)

  1. 职责链模式:使多个对象都有机会处理请求,解除请求发送者和接收者的耦合。将对象连成一条链,并沿这条链传递请求直到请求被解决。
  2. 请求交付给最小接受者,职责链中每一环保存后继的引用,使得请求有序沿链传递。
    通过合理设置后继以及分支关系,避免一个请求到了链末端依旧无法被处理,或因配置错误得不到处理的情况。

策略模式(Strategy)

  1. 面向对象中并非类越多越好,类的划分是为了封装,但分类的基础是抽象,具有相同属性和功能的对象的抽象集合才是类。
  2. 策略模式:定义算法家族并分别封装,他们完成的工作相同,只是实现不同,可以互相替换。继承有助于析取这些算法的公共功能。此模式让算法的变化不会影响到使用算法的用户。
  3. 策略与工厂模式结合,使客户端需要认识的类减少,耦合度更加降低。
  4. 策略模式可以简化单元测试,因为每个算法可以通过自己的接口单独测试。
  5. 只要在不同时间内应用不同的业务规则,就可以考虑用策略模式来处理这种变化的可能性。

状态模式(State)

  1. 拥有过多分支的过长方法违背了单一职责原则,而且当需求变化时修改代码往往会违背开放-封闭原则,应该将分支变成一不同小类,将状态的判断逻辑转移到小类中。
  2. 状态模式:一个对象可能拥有多种状态,当内在状态改变时允许改变行为。
  3. 状态模式的好处是将与特定状态有关的行为局部化,并将不同状态的行为分隔开。

观察者模式(Observer)

  1. 观察者模式:多个观察者对象同时监听某一主题(通知者)对象,当该主题对象状态变化时会通知所有观察者对象,使它们能更新自己。
  2. 具体观察者保存一个指向具体主题对象的引用,抽象主题保存一个抽象观察者的引用集合,提供一个可以添加或删除观察者的接口。
  3. 抽象模式中有两方面,一方面依赖另一方面,使用观察者模式可将两者独立封装,解除耦合。
  4. 观察者模式让主题和观察者双方都依赖于抽象接口,而不依赖于具体。
  5. 委托就是一种引用方法类型。委托可看作函数的类,委托的实例代表具体函数。在主题对象内声明委托,不再依赖抽象观察者。
    一个委托可以搭载多个相同原形和形式(参数和返回值)的方法,这些方法不需要属于一个类,且被依次唤醒。

迭代器模式(Iterator)

  1. 迭代器模式:提供一种方法顺序遍历一个聚集对象,为不同的聚集结构提供遍历所需接口,而不暴露对象内部的表示。
  2. 在高级编程语言如c#、c++、java等,都已经把迭代器模式设计进语言的一部分。
  3. 迭代器模式分离了对象的遍历行为,既不暴露内部结构又可以让外部代码透明的访问集合内部的数据。

备忘录模式(Memento)

  1. 备忘录模式:不破坏封装,获取对象内部状态并在其之外保存该对象,以便其未来恢复到当前状态。
  2. Orginator负责创建Memento,Memento封装Originator状态细节,Caretaker负责保管和交付Memento。
  3. 备忘录模式适用于需要维护历史状态的对象,或只需要保存原类属性中的小部分。

命令模式(Command)

  1. 命令模式:将请求分装为对象,将请求和执行分开,可以用不同的请求对客户参数化。可以对请求排队、通过或否决、记录日志、撤销或重做。
  2. 基于敏捷开发原则,不要给代码添加基于猜测而实际不需要的功能,在需要的时候通过重构实现。

模板方法模式(Template Method)

  1. 模板方法模式:定义一个操作中的算法框架,将一些步骤延迟到子类中。子类在不改变框架的前提下就可以重新定义某些特定步骤。
  2. 当不变和可变的行为在子类中混到一起时,可以通过把重复的行为移到同一地方,帮助子类摆脱重复不变行为的纠缠。

中介者模式(Mediator)

  1. 中介者模式:用一个中介对象来封装一系列对象间的交互。
  2. 中介者模式在系统中易用也容易被误用,当系统中出现了多对多的交互复杂的对象群时,更应考虑设计的问题。
  3. 由于控制集中化,中介者模式将交互复杂性变成了中介者的复杂性,中介者类会比任何一个同事类都复杂。
  4. 中介者模式应用的场合有,一组对象以定义良好但复杂的方式进行通信,以及想定制一个分布在多个类中的行为却不想产生太多子类。

解释器模式(Interpreter)

  1. 解释器模式:给定一种语言,定义它文法的一种表示,再定义一个解释器,使用该表示来解释语言中的句子。
  2. 如果一种特定类型发生的频率足够高,就可以将其实例表达为一个句子,构建解释器来解析。
  3. 解释器模式就是用“迷你语言”来表现程序要解决的问题,将句子抽象为语法树。由于各个节电的类大体相同,便于修改、扩展和实现。
  4. 解释器为文法中的每条规则定义了一个类,当文法过多时将难以维护,建议使用其他技术如语法分析程序或编译器生成器处理。

访问者模式(Visitor)

  1. 访问者模式:在不改变各元素的前提下定义作用于这些类的新的操作。
  2. 访问者模式使用双分派,将数据结构和作用于结构上的操作解耦,意味着执行的操作决定于请求的种类和接收者的状态。
  3. 如果系统具有较为稳定的数据结构,又有易于变化的算法操作,则适合使用访问者模式。

对比总结

  • 工厂方法模式:为不同子类创建不同工厂;
  • 抽象工厂模式:为不同系列建造不同工厂;
  • 单例模式:保证实例唯一;
  • 建造者模式:为不同类组装出一套相同的方法;
  • 原型模式:实现深拷贝。

  • 代理模式:控制访问;
  • 适配器模式:将接口转换为客户端期望的形式;
  • 外观模式:整理出一套可用接口;
  • 装饰模式:动态修改类的职能;
  • 桥接模式:将多角度分类分离独立;
  • 享元模式:共享实例;
  • 组合模式:递归生成树形结构的组合对象。
  • 职责链模式:按顺序让负责的对象们依次处理;
  • 策略模式:将算法族抽象封装;
  • 状态模式:将复杂的状态转移方式下发到每个状态内部;
  • 观察者模式:发布和订阅;
  • 迭代器模式:遍历容器;
  • 备忘录模式:在对象之外备份及恢复;
  • 命令模式:封装请求与执行分开;
  • 模板方法模式:提炼共有方法。
  • 中介者模式:用中介对象封装交互。
  • 解释器模式:迷你语言;
  • 访问者模式:解耦数据结构及操作。




作者:尤汐Yogy
链接:https://www.jianshu.com/p/0b2a6ec0ee3d
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

更多C/C++Linux后台开发架构体系学习文章请关注笔者:

Linux后台开发狮​www.zhihu.com/people/linux-9-85正在上传…重新上传取消

笔者会不断更新C/C++Linux后台开发架构体系,程序员面试经验以及答题答案总结分享;敬请关注更新。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值