设计模式面试

C++ 面向对象设计
  • 封装:隐藏内部实现
  • 继承:复用现有代码
  • 多态:改写对象行为

设计模式关键在于分解和抽象;

设计模式的主要目的是易于变化

面向对象设计原则–比设计模式更加重要 违背了设计原则,设计模式是错误的。

  • 依赖倒置原则(DIP)
  • 开放封闭原则(OCP)
  • 单一职责原则(SRP)
工厂方法模式
模式定义

工厂方法模式(Factory Method Pattern)又称为工厂模式,也叫虚拟构造器(Virtual Constructor)模式或者多态工厂(Polymorphic Factory)模式,它属于类创建型模式。在工厂方法模式中,工厂父类负责定义创建产品对象的公共接口,而工厂子类则负责生成具体的产品对象,这样做的目的是将产品类的实例化操作延迟到工厂子类中完成,即通过工厂子类来确定究竟应该实例化哪一个具体产品类。

模式结构和时序图
  • Product:抽象产品
  • ConcreteProduct:具体产品
  • Factory:抽象工厂
  • ConcreteFactory:具体工厂

模式结构:

模式结构

工厂方法模式的优点
  • 工厂无需关心细节,甚至无序知道具体产品的类名称。
  • 工厂角色和茶农角色的多态性设计是工厂方法模式的关键。它能确定创建的产品对象;创建细节完全封装在具体工厂内部。所有的具体工厂类都具有同一抽象父类。
  • 添加新产品时,只需要添加一个具体的工厂和具体产品就可以了,系统的扩展性较好,完全符合”开闭原则”。
工厂模式的缺点
  • 添加新产品时,需要编写新的具体产品类,而且需要提供与之赌赢的工厂类,系统中类的个数将成对增加,会带来额外的编译开销。
  • 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。
单例模式
模式定义

单例模式(Singleton Pattern):单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。

单例模式的要点有三个:一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。单例模式是一种对象创建型模式。单例模式又名单件模式或单态模式。

模式分析

单例模式的目的是保证一个类仅有一个实例,并提供一个访问它的全局访问点。单例类拥有一个私有构造函数,确保用户无法通过new关键字直接实例化它。除此之外,该模式中包含一个静态私有成员变量与静态公有的工厂方法,该工厂方法负责检验实例的存在性并实例化自己,然后存储在静态成员变量中,以确保只有一个实例被创建。

在单例模式的实现过程中,需要注意如下三点:

  • 单例类的构造函数为私有;
  • 提供一个自身的静态私有成员变量;
  • 提供一个公有的静态工厂方法。
优点
  • 提供了对唯一实例的受控访问。
  • 允许可变数目的实例。
缺点
  • 由于单例模式中没有抽象层,因此单例类的扩展有很大的困难。
  • 单例类的职责过重,在一定程度上违背了“单一职责原则”。
适用环境
  • 系统只需要一个实例对象,如系统要求提供一个唯一的序列号生成器,或者需要考虑资源消耗太大而只允许创建一个对象。
观察者模式

上述模式中,需要使用明显的调用函数,来进行两个对象之间的通信,但是能否建立一种关系,使得一个对象发生改变时,自动通知其它对象,做出反映。这种模式就是观察者模式

模式定义

观察者模式(Observer Pattern):定义对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者模式又叫做发布-订阅(Publish/Subscribe)模式。

观察者模式是一种对象行为型模式。

模式结构

观察者模式包含如下角色:

  • Subject: 目标主题:跟踪所有观察者,并提供添加和删除观察者的接口。
  • ConcreteSubject: 具体目标;将有关状态存入各 ConcreteObserver 对象。当具体主题的状态发生任何更改时,通知所有观察者。
  • Observer: 观察者:为所有的具体观察者定义一个接口,在得到主题的通知时进行自我更新。
  • ConcreteObserver: 具体观察者;实现 Observer 所要求的更新接口,以便使本身的状态与主题的状态相协调。

类图如下:

观察者类图

优缺点

优点:

  • 观察者和被观察者是抽象耦合的

缺点:

  • 如果一个被观察者对象有很多的直接和间接的观察者,将所有的观察者都通知到会花费很多时间。
  • 如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
适用情况
  • 一个对象必须通知其他对象,而并不知道这些对象是谁。
代理模式
模式定义

代理模式(Proxy Pattern) :给某一个对象提供一个代 理,并由代理对象控制对原对象的引用。代理模式的英文叫做Proxy或Surrogate,它是一种对象结构型模式。

模式结构

代理模式包含角色如下:

  • Subject:抽象主题角色;声明了 RealSubject 与 Proxy 的共同接口,定义了某个/些功能。
  • RealSubject(真实主题):通常执行具体的业务逻辑,Proxy 控制对它的访问。
  • Proxy:持有一个 RealSubject 引用(指针),可以在需要时将请求转发给 RealSubject,以此起到代理的作用。
  • Client(客户端):通过 Proxy 间接地与 RealSubject 进行交互。

注意: Proxy 和 RealSubject 都实现了 Subject 的接口,这允许 Client 可以像处理 RealSubject 一样处理 Proxy。

结构模式类图

优缺点

优点:

  • 代理模式能将代理对象与真正被调用的对象分离,在一定程度上降低了系统的耦合度。
  • 在客户端和目标对象之间,代理起到一个中介作用,这样可以保护目标对象。在对目标对象调用之前,代理对象也可以进行其他操作。

缺点:

  • 这种模式引入了另一个抽象层,这有时可能是一个问题。如果真实主题被某些客户端直接访问,并且其中一些客户端可能访问代理类,这可能会导致不同的行为。
  • 由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。
  • 实现代理模式需要额外的工作,有些代理模式的实现非常复杂。
适用场景
  • 远程代理(Remote Proxy):为一个位于不同地址空间的对象提供一个本地代理,对代理的方法调用会导致对远程对象的方法调用。ATM 就是一个例子,ATM 可能会持有(存在于远程服务器中的)银行信息的一个代理对象。
  • 虚拟代理(Virtual Proxy):使用虚拟代理,代理可以作为一个(资源消耗较大的)对象的代表。虚拟代理经常延迟对象的创建,直到需要为止。在创建对象之前(及创建对象过程中),虚拟代理也可以作为对象的代理;之后,代理将请求直接委托给 RealSubject。
  • 保护代理(Protection Proxy):根据访问权限,可以使用保护代理来控制对资源的访问。
装饰模式

对于类或者对象的行为增加,一般有两种方式:

  • 继承机制:使用继承机制,直接进行函数的添加。
  • 关联机制,即将一个类的对象嵌入另外一个对象中,由另外一个对象来决定是否调用嵌入对象的行为,以便扩展自己的行为。,我们称这个嵌入的对象为“装饰器”。
模式定义:

装饰模式(Decorator Pattern) :动态地给一个对象增加一些额外的职责(Responsibility),就增加对象功能来说,装饰模式比生成子类实现更为灵活。其别名也可以称为包装器(Wrapper),与适配器模式的别名相同,但它们适用于不同的场合。根据翻译的不同,装饰模式也有人称之为“油漆工模式”,它是一种对象结构型模式。

模式结构

包含角色如下:

  • Component: 抽象构件
  • ConcreteComponent: 具体构件
  • Decorator: 抽象装饰类
  • ConcreteDecorator: 具体装饰类

结构模式图

装饰模式中的装饰类一般拥有为抽象构建成员,通过具体构建类来进行添加操作,成为具体的装饰类,最终实现具体的类操作的扩展,装饰器一般也来自于基础的抽象构件

优点
  • 装饰模式提供比继承更多的灵活度
缺点
  • 使用装饰模式时,因为层层递进关系,会产生很多无用的小对象;和具体的装饰类。
适配器模式

适配器模式(Adapter Pattern) :将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。

适配器模式(Adapter Pattern)是一种补救模式,将一个类的接口转换成客户希望的另外一个接口,从而使原本由于接口不兼容而不能一起工作的类可以一起工作。

1.3 模式结构

适配器模式包含如下角色:

  • Target:目标抽象类
  • Adapter:适配器类
  • Adaptee:适配者类
  • Client:客户类

适配器模式有对象适配器和类适配器两种实现:

对象适配器:

对象适配器

优点
  • 将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,而无须修改原有代码。
  • 增加了类的透明性和复用性。

对象适配器模式还具有如下优点: 一个对象适配器可以把多个不同的适配者适配到同一个目标,也就是说,同一个适配器可以把适配者类和它的子类都适配到目标接口。

缺点
  • 对象适配器:
    -mWsqMa1A-1704852256417)]
优点
  • 将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,而无须修改原有代码。
  • 增加了类的透明性和复用性。

对象适配器模式还具有如下优点: 一个对象适配器可以把多个不同的适配者适配到同一个目标,也就是说,同一个适配器可以把适配者类和它的子类都适配到目标接口。

缺点
  • 对象适配器:
    • 与类适配器模式相比,要想置换适配者类的方法就不容易。如果一定要置换掉适配者类的一个或多个方法,就只好先做一个适配者类的子类,将适配者类的方法置换掉,然后再把适配者类的子类当做真正的适配者进行适配,实现过程较为复杂。

相关推荐

  1. 设计模式-面试

    2024-01-11 17:26:04       36 阅读
  2. 面试设计模式

    2024-01-11 17:26:04       18 阅读
  3. 设计模式面试专题

    2024-01-11 17:26:04       18 阅读
  4. 设计模式面试系列-02

    2024-01-11 17:26:04       31 阅读
  5. 设计模式面试题(一)

    2024-01-11 17:26:04       16 阅读
  6. 设计模式面试题(二)

    2024-01-11 17:26:04       15 阅读
  7. 设计模式面试题(七)

    2024-01-11 17:26:04       17 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-01-11 17:26:04       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-01-11 17:26:04       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-01-11 17:26:04       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-01-11 17:26:04       20 阅读

热门阅读

  1. 如何防止 DNS 攻击造成的损失

    2024-01-11 17:26:04       32 阅读
  2. PostgreSQL 归档和基于时间点恢复

    2024-01-11 17:26:04       30 阅读
  3. go 语言常见问题(2)

    2024-01-11 17:26:04       36 阅读
  4. 并发编程(一)

    2024-01-11 17:26:04       33 阅读
  5. What does rpm do?

    2024-01-11 17:26:04       38 阅读
  6. Linux 之间通过 SSH 传输文件

    2024-01-11 17:26:04       31 阅读
  7. linux踢掉远程登录用户*

    2024-01-11 17:26:04       36 阅读
  8. 【Unity】优化 if else 和 Switch Case

    2024-01-11 17:26:04       33 阅读