欢迎光临散文网 会员登陆 & 注册

面试中c++ 常用设模式

2023-03-29 21:32 作者:bili_3493270558607894  | 我要投稿
  1. 单例模式(Singleton Pattern)

  2. 工厂模式(Factory Pattern)

  3. 策略模式(Strategy Pattern)

  4. 观察者模式(Observer Pattern)

  5. 访问者模式(Visitor Pattern)

  6. 建造者模式(Builder Pattern)

  7. 适配器模式(Adapter Pattern)

  8. 桥接模式(Bridge Pattern)

  9. 装饰器模式(Decorator Pattern)

  10. 组合模式(Composite Pattern)

  11. 迭代器模式(Iterator Pattern)

  12. 外观模式(Facade Pattern)

  13. 职责链模式(Chain of Responsibility Pattern)

  14. 命令模式(Command Pattern)

  15. 解释器模式(Interpreter Pattern)

  16. 中介者模式(Mediator Pattern)

1.单例模式(Singleton Pattern)

单例模式是一种创建型设计模式,它保证一个类只有一个实例,并提供全局访问点。

单例模式的主要思想是通过私有化类的构造器,使得外部无法直接创建该类的实例。然后在类内部维护一个唯一的实例,并提供一个静态方法用于获取该实例。这样,在整个应用程序中,只有一个实例存在,所有需要使用该实例的地方都可以通过该静态方法获取到该实例。

单例模式主要有两种实现方式:懒汉式和饿汉式。懒汉式单例模式在第一次调用静态方法时才创建实例,而饿汉式单例模式则在类加载时就创建了实例。

单例模式的优点包括:

  1. 提供唯一实例,减少内存消耗。

  2. 简化了代码,避免了多个实例之间的冲突。

  3. 可以控制全局资源的并发访问。

单例模式的缺点包括:

  1. 因为单例模式控制了实例的数量,所以可能会导致系统扩展困难。

  2. 单例模式增加了程序的复杂度,降低了代码的灵活性。

  3. 单例模式在多线程环境下使用时需要考虑线程安全问题。

2.工厂模式(Factory Pattern)

工厂模式是一种创建型设计模式,它提供了一种创建对象的最佳方式。工厂模式通过使用工厂方法来处理创建对象的过程,并将这个过程推迟到子类中,从而使得主要的代码逻辑与实例化解耦。这意味着在程序运行时,可以改变对象的类型而不影响主要的代码逻辑。

在工厂模式中,我们定义一个工厂接口以及该接口的实现类。这个工厂接口和实现类负责创建某些类的实例。然后我们使用这个工厂来创建对象并且隐藏创建的过程。这样做的好处是如果我们需要改变对象的类型,我们只需要改变工厂的实现,而无需修改调用者的代码。

总之,工厂模式使得代码更加灵活、可扩展、易于维护,并且可以减少代码重复。常见的工厂模式有简单工厂模式、工厂方法模式和抽象工厂模式。

3.策略模式(Strategy Pattern)

策略模式是一种行为型设计模式,它允许在运行时动态地改变对象的行为。策略模式将算法与其实现分离,使得算法可以独立于其使用者而变化。

在策略模式中,我们定义了一个抽象的策略接口,以及一些具体的策略类来实现这个接口。然后我们创建一个上下文类,该类包含一个指向策略接口的引用。在运行时,我们可以动态地改变上下文类中的策略引用,从而改变其行为。

策略模式的好处是可以将不同的算法封装到不同的策略类中,从而避免了代码的重复。另外,由于策略类是相互独立的,所以我们可以通过增加新的策略类来扩展系统的功能。

常见的应用场景包括排序算法、搜索算法、压缩算法等等。例如,在一个排序系统中,我们可以定义一个排序接口和多个具体的排序策略类来实现不同的排序算法,然后在运行时根据需要选择合适的排序策略来对数据进行排序。

总之,策略模式使得程序更加灵活、可扩展,并且提高了代码的可维护性。

4.观察者模式(Observer Pattern)

观察者模式是一种设计模式,用于在对象之间定义一对多的依赖关系,使得当一个对象改变状态时,它的所有依赖者都能收到通知并自动更新。

该模式包含两个主要角色:Subject(被观察者)和Observer(观察者)。Subject维护着一组观察者,并提供了添加和删除观察者的接口。当Subject的状态发生改变时,它会通知所有观察者,并在通知中传递状态信息。Observer则实现了一个更新接口,以便能够接收Subject的通知并进行相应的处理。

观察者模式有以下优点:

1.松耦合:Subject和Observer之间是松耦合的,它们之间的关系通过抽象接口建立,从而使它们可以独立地改变和扩展。

2.可重用性:Subject和Observer可以被多次重用,因为它们之间的关系是抽象的。

3.灵活性:Subject和Observer之间可以动态地建立和解除关系,因此它们之间的交互可以在运行时动态地改变。

4.增强了对象的一致性:Subject和Observer之间的关系使得它们共同构成了一个整体,即使系统中的其他部分发生改变,它们之间的关系也不会受到影响。

观察者模式在很多地方都有应用,比如GUI编程、事件处理等。例如,在GUI编程中,当用户点击某个按钮时,该按钮可以充当Subject,而该按钮上的所有组件(包括标签、文本框等)可以充当Observer,这些组件将根据按钮的状态自动更新自己的内容。

5.访问者模式(Visitor Pattern)

访问者模式是一种行为型设计模式,它允许你定义一些操作,这些操作可以应用于不同的对象结构中的元素。通过这种方式,你可以在不改变各个元素类别或这些类别之间的关系的情况下,向现有对象结构添加新的操作。

简单来说,访问者模式就是将某些操作(访问者)与数据结构(被访问者)分离开来,从而使得操作和数据结构能够独立地变化,扩展性更好。

在访问者模式中,数据结构中的每个元素都拥有一个 accept 方法,该方法会接受访问者作为参数,并调用访问者的 visit 方法来执行具体的操作。访问者则需要实现与不同元素类型相对应的多个 visit 方法,以便在访问时执行正确的操作。

使用访问者模式可以有效地减少代码重复,并且支持在运行时动态地添加新的操作。但同时也会增加代码的复杂度,因此需要慎重选择是否使用该模式。

6.建造者模式(Builder Pattern)

建造者模式是一种创建型设计模式,它允许你在不同的对象上使用相同的构建代码来创建不同的表示形式。该模式将对象的构建过程分离出来,并且使得可以通过单独的方式创建和组合复杂的对象。

简单来说,建造者模式就是将一个复杂对象的构建过程与其表示分离开来,使得同样的构建过程可以创建不同的表示。

在建造者模式中,通常会定义一个 Builder 接口,这个接口包括所有必须实现的方法,用于指定要构建的每个部分。然后有一个具体的 Builder 类,它实现了 Builder 接口并包含了具体的构建逻辑。最终,有一个 Director 类,它负责使用 Builder 对象来构建最终的对象,并且根据需要可以通过改变 Builder 对象来修改构建结果。

使用建造者模式可以有效地解耦构建过程和最终表示,增加代码的可读性和可维护性。但同时也会增加工作量和代码量,因此需要慎重选择是否使用该模式。

7.适配器模式(Adapter Pattern)

适配器模式是一种结构型设计模式,它允许你将不兼容的对象包装在适配器中,以便它们能够协同工作。该模式将目标类和不兼容的类进行适配,使得目标类能够使用不兼容的类的功能。

简单来说,适配器模式就是通过一个适配器来转换一种接口到另一种接口,使得原本不兼容的类可以协同工作。

在适配器模式中,通常会有一个目标接口和一个适配器类。目标接口定义了客户端使用的接口,而适配器类则实现了目标接口,并且包含了一个不兼容的类的实例。适配器类需要将客户端调用的方法转换为不兼容类的方法调用,以实现目标接口。

使用适配器模式可以有效地解决不兼容的问题,并且可以减少代码修改的影响范围。但同时也会增加代码的复杂度,因此需要慎重选择是否使用该模式。

8.桥接模式(Bridge Pattern)

桥接模式是一种结构型设计模式,它的主要目的是将一个大类或复杂的类分解成两个或多个简单的类,这些简单的类可以独立地进行修改和维护。桥接模式通过组合关系(而不是继承关系)连接这些简单的类,从而实现了大类或复杂类的功能。

桥接模式中的核心概念是“桥”,它允许客户端代码使用抽象接口而不必关心具体实现。在桥接模式中,抽象部分和实现部分可以分别独立地扩展,从而使得系统更加灵活和可扩展。

桥接模式适用于以下几种情况:

  1. 当一个类具有多个变化因素时,可以使用桥接模式将这些变化因素分离出来,从而使得系统更加灵活和可扩展。

  2. 当需要在多个平台之间共享代码时,可以使用桥接模式来保持各个平台的独立性。

  3. 当需要支持多种数据源时,可以使用桥接模式来将数据源和数据处理逻辑分离开来。

桥接模式的优点包括:

  1. 桥接模式可以减少类的数量,降低系统的复杂度。

  2. 桥接模式可以提高系统的灵活性和可扩展性,因为抽象部分和实现部分可以独立地进行修改和扩展。

  3. 桥接模式可以使得系统更加稳定和可靠,因为抽象部分和实现部分是分离的,一个部分的变化不会影响到另一个部分。

桥接模式的缺点包括:

  1. 桥接模式需要额外的编码工作,因为需要定义抽象部分和实现部分之间的桥接接口。

  2. 桥接模式增加了系统的复杂度,因为需要对系统进行分层设计。


9.装饰器模式(Decorator Pattern)

装饰器模式是一种结构型设计模式,它允许在不修改现有对象的情况下,动态地将行为添加到对象中。装饰器模式的核心思想是通过包装(即装饰)一个对象来扩展其功能。

在装饰器模式中,有一个基础组件(Component)和多个装饰器(Decorator)。基础组件是被装饰的对象,而装饰器则用于包装这个对象,并添加额外的行为。每个装饰器都实现了与基础组件相同的接口,从而可以像基础组件一样被使用。

举个例子,假设你正在开发一个咖啡店应用程序,其中有一个基础咖啡(Coffee)类。现在,你需要添加一些调料,比如牛奶、糖等。你可以使用装饰器模式来实现:创建一个调料装饰器(CondimentDecorator)类作为基础装饰器,然后创建具体的调料装饰器类(MilkDecorator、SugarDecorator等),并将它们包装在基础咖啡(Coffee)对象上。

优点:

  1. 装饰器模式避免了在代码中添加大量子类的情况,提高了代码灵活性和可维护性。

  2. 装饰器模式可以动态地添加或删除对象的行为,而不会影响其他对象。

  3. 装饰器模式遵循开放封闭原则(OCP),可以在不修改现有代码的情况下扩展对象的功能。

缺点:

  1. 使用装饰器模式可能会导致过多的小类,这可能会使代码变得更加复杂。

  2. 装饰器模式增加了代码的复杂性和理解难度。

适用场景:

  1. 当需要动态地添加或删除对象的行为时,可以使用装饰器模式。

  2. 当需要扩展一个类的功能,但是不希望修改其代码时,可以使用装饰器模式。

  3. 当需要在运行时动态地给对象添加功能,并且通过继承来扩展对象功能并不切实际时,可以使用装饰器模式。

10.组合模式(Composite Pattern)

组合模式是一种结构型设计模式,它允许将对象组合成树形结构以表示"部分-整体"关系,使客户端能够以统一的方式处理单个对象和组合对象。

在组合模式中,有两种类型的对象:叶子节点和组合节点。叶子节点表示树形结构中最基本的元素,它们没有子节点;而组合节点表示由多个子节点组成的复杂对象,它们可以包含任意数量和类型的子节点。这样就可以通过递归遍历整个树形结构来处理每个节点。

组合模式的优点在于它简化了客户端的代码,并且增加新的节点类型也非常容易。缺点在于可能会导致过度设计,因为它将单个对象和组合对象视为等价的。此外,组合模式还需要考虑处理叶子节点的情况,以确保递归不会陷入死循环。

11.迭代器模式(Iterator Pattern)

迭代器模式是一种行为型设计模式,它提供了一种访问集合对象中各个元素的方法,而不需要暴露该对象的内部实现细节。

迭代器模式有两个核心角色:迭代器和可迭代对象。迭代器是一个用于遍历集合对象的接口,定义了访问集合中各个元素的方法;而可迭代对象是一个包含多个元素的集合对象,通常实现了一个返回迭代器的方法,使得客户端可以通过迭代器逐个访问集合中的元素。

迭代器模式的主要优点在于它将集合对象和遍历算法分离开来,使得它们可以独立变化。这样就可以方便地添加新的遍历方式或者更换底层集合结构,同时也保证了代码的可读性和可维护性。缺点在于迭代器模式会增加代码的复杂性,因为需要额外的类和接口来实现遍历功能,同时也可能会牺牲一些执行效率。

迭代器模式在实际应用中非常广泛,例如在Java的集合框架中就使用了Iterator接口来实现集合的遍历。

12.外观模式(Facade Pattern)

外观模式是一种结构型设计模式,它提供了一个简化的接口,用于访问复杂系统中的一组接口。这个简化的接口就像是一个"外观",隐藏了系统的复杂性,并向客户端提供了一组更简单、更易用的操作。

外观模式有一个核心角色:外观类。外观类是一个具有简化接口功能的高层接口,它封装了系统的复杂性,向客户端提供了一个更为简单和易用的接口。通常情况下,外观类会调用一组低层次的子系统接口来完成它所需要的功能。客户端只需要与外观类进行交互,而不需要知道系统内部的复杂细节。

外观模式的主要优点在于它可以帮助客户端减少与复杂系统的耦合度,从而提高代码的可读性和可维护性。同时它还能够简化客户端的代码,使得客户端能够更加容易地使用系统。缺点在于它可能会造成系统的性能损失,因为外观类通常需要调用一组低层次的子系统接口来完成它所需要的功能。

外观模式在实际应用中非常广泛,例如在Java中的Servlet API中就使用了外观模式,将所有与Servlet请求相关的操作都封装在javax.servlet.http.HttpServletRequest和javax.servlet.http.HttpServletResponse中。这样就能够简化客户端代码,并减少对底层实现细节的依赖。

13.职责链模式(Chain of Responsibility Pattern)

职责链模式是一种行为型设计模式,它允许多个处理器对象逐个处理某个请求,直到其中一个处理器能够处理该请求为止。职责链模式的核心思想是将请求和处理器解耦,从而使得请求可以沿着处理器链依次传递,直到找到一个可以处理该请求的处理器为止。

职责链模式有三个核心角色:抽象处理器、具体处理器和客户端。抽象处理器定义了一个接口,用于处理请求和设置下一个处理器;具体处理器实现了抽象处理器接口,并负责处理特定类型的请求;客户端创建处理器链,并向链的开头发送请求。当请求到达链的某个处理器时,该处理器会尝试处理请求,如果无法处理该请求,则将请求传递给下一个处理器。

职责链模式的主要优点在于它能够动态地调整和扩展处理器链,同时还能够避免请求发送者和接收者之间的显式耦合关系。缺点在于它可能会导致请求被多次处理或者完全无法处理,因此需要谨慎设计处理器链,以确保每个请求都能够得到正确的处理。

职责链模式在实际应用中非常广泛,例如Java中的Servlet Filter就是一种职责链模式的实现,用于在Web应用中处理HTTP请求和响应。

14.命令模式(Command Pattern)

命令模式是一种行为型设计模式,它将请求封装成一个对象,并将操作的执行者和接收者分离开来。命令模式允许请求发送者与接收者松散耦合,从而使得系统更加灵活。

在命令模式中,有四个核心角色:命令、具体命令、调用者和接收者。命令是一个抽象类或接口,定义了执行操作的方法;具体命令实现了命令接口,并封装了一个接收者和一个操作;调用者负责创建和存储命令对象,并向命令对象发送执行请求;接收者负责执行实际的操作。

命令模式的主要优点在于它能够将请求者和接收者解耦,使得系统更加灵活。例如,在GUI应用程序中,可以使用命令模式来实现一组撤销/重做功能,从而允许用户撤销最近的操作。缺点在于命令对象可能会导致系统复杂化,因为需要创建多个命令对象,并将它们连接在一起。

命令模式在实际应用中也有很多的使用场景,例如Java中的AWT事件处理机制就使用了命令模式,每个AWT组件都有一个addActionListener()方法,用于为该组件添加一个ActionListener对象,当用户触发该组件时,会调用ActionListener对象的actionPerformed()方法。

15.解释器模式(Interpreter Pattern)

解释器模式是一种行为型设计模式,它可以用来解释一些特定的语法规则。这种模式通常用于处理自然语言或数学表达式等问题。

在解释器模式中,有两个核心角色:抽象表达式和具体表达式。抽象表达式定义了一个解释器的接口,包含了一个interpret()方法;具体表达式实现了抽象表达式接口,并负责解析和执行特定的语法规则。

解释器模式的主要优点在于它能够简化语法规则的解析和执行,并提供了灵活性和可扩展性。缺点在于它可能会导致代码变得复杂,因为需要创建多个类来表示不同的语法规则,并且每个具体表达式都需要实现interpret()方法。

解释器模式在实际应用中也有一些使用场景,例如在编译器、数据库查询、正则表达式等领域中都有应用。例如,在编译器中,解释器模式可以用来将源代码转换成中间代码或机器代码。

16.中介者模式(Mediator Pattern)

中介者模式是一种行为型设计模式,它允许对象之间进行通信,而不需要直接相互引用。中介者模式通过封装对象之间的交互,从而使得这些对象可以松散耦合,并且可以独立地改变它们之间的交互方式。

在中介者模式中,有三个核心角色:中介者、抽象同事类和具体同事类。中介者定义了一个接口,用于与各个同事对象通信;抽象同事类定义了一个接口,用于向中介者发送消息;具体同事类实现了抽象同事类接口,并负责处理特定类型的消息。

中介者模式的主要优点在于它能够降低系统的复杂度,因为它将对象之间的交互抽象成一个中介者对象,从而减少了对象之间的直接依赖关系。同时它还可以方便地扩展系统,因为可以通过增加或修改中介者来改变对象之间的交互方式。缺点在于它可能会导致中介者对象变得过于复杂,因为需要处理各种不同的消息类型。

中介者模式在实际应用中也有很多的使用场景,例如在GUI程序中,可以使用中介者模式来管理不同组件之间的交互,从而使得程序更加易于维护和扩展。


面试中c++ 常用设模式的评论 (共 条)

分享到微博请遵守国家法律