我是靠谱客的博主 朴实小兔子,最近开发中收集的这篇文章主要介绍C++面经-设计模式设计模式,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

面经-设计模式

  • 设计模式
    • Q1 请问你用过哪些设计模式
    • Q2 单例模式的多线程安全问题
    • Q3 请你说一说OOP(面向对象编程)的设计模式的五项原则

设计模式

Q1 请问你用过哪些设计模式

  • 常见的设计模式如下(主要前四个):
  1. 单例模式:单例模式主要解决一个全局使用的类频繁的创建和销毁的问题。单例模式下可以确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。单例模式有三个要素:一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。
    优点:1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。 2、避免对资源的多重占用(比如写文件操作)。
    缺点:没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。
    注意事项:getInstance() 方法中需要使用同步锁 synchronized (Singleton.class) 防止多线程同时进入造成 instance 被多次实例化。

  2. 工厂模式:是最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式。工厂模式主要解决接口选择的问题。该模式下定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,使其创建过程延迟到子类进行。
    优点:解耦,代码复用,更改功能容易。

  3. 观察者模式:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
    补充:观察者模式中分为观察者和被观察者,当被观察者发生装填改变时,观察者会受到通知。主要为了解决对象状态改变给其他对象通知的问题,其实现类似于观察者在被观察者那注册了一个回调函数。

  4. 装饰器模式:创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能,从而动态的为一个对象增加新的功能。装饰器模式是一种用于代替继承的技术,无需通过继承增加子类就能扩展对象的新功能。使用对象的关联关系代替继承关系,更加灵活,同时避免类型体系的快速膨胀。
    优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
    缺点:多层装饰比较复杂。
    使用场景:1、扩展一个类的功能。 2、动态增加功能,动态撤销。

  5. 适配器模式Adeque
    一种容器可以完全的满足另一种容器需要的功能,如deque能完全满足queue。只需改一些deque接口即可

  6. Prototype设计模式-原型模式
    一个继承体系,想去创建未来才会出现的子类。即现在要去创建未来的class对象

  7. 组合模式-Comosite模式
    计算机文件系统中,我们可以将文件夹和文件看作同一种类型的对象,同城为目录条目,方便我们处理递归问题,容器中既可以放入容器,又可以放入内容,然后在小容器中,又可以继续放入容器和内容,构成了一种递归结构和容器结构,而组合模式就是创造出这样的容器结构。

Q2 单例模式的多线程安全问题

等同于:请问如何保证单例模式只有唯一实例? / 你知道的都有哪些方法

  • 出现什么问题:在单例模式的实现中,如果不采取任何措施,在多线程下是不安全的,可能会同时创建多个实例。因此,为了保证单例模式在多线程下的线程安全,一般采用下面两种方式实现单例模式:
  1. 饿汉式:基于class loader机制避免多线程的同步问题,通过局部静态变量,利用其只初始化一次的特点,返回对象。
    将该类的构造方法定义为私有方法,这样其他处的代码就无法通过调用该类的构造方法来实例化该类的对象,只有通过该类提供的静态方法来得到该类的唯一实例;不过,instance在类装载时就实例化,可能会产生垃圾对象。
    特点:饿了肯定要饥不择食。所以在单例类定义的时候就进行实例化。因为main函数执行之前,全局作用域的类成员静态变量m_Instance已经初始化,故没有多线程的问题。
    饿汉式

  2. 懒汉式:通过双重锁机制实现线程安全。加同步锁前后两次判断实例是否存在(在没有必要的时候不加锁,耗时)
    在该类内提供一个静态方法,当我们调用这个方法时,如果类持有的引用不为空就返回这个引用,如果类保持的引用为空就创建该类的实例并将实例的引用赋予该类保持的引用
    特点:延迟加载,比如配置文件,采用懒汉式的方法,顾名思义,懒汉么,很懒的,配置文件的实例直到用到的时候才会加载,不到万不得已就不会去实例化类,也就是说在第一次用到类实例的时候才会去实例化。
    如果并发访问怎么做:使用锁机制,防止多次访问,可以这样,第一次判断为空不加锁,若为空,再进行加锁判断是否为空,若为空则生成对象。
    懒汉式

  • 懒汉式和饿汉式区别

  • 实例化方面:懒汉式默认不会实例化,外部什么时候调用什么时候new。饿汉式在类加载的时候就实例化,并且创建单例对象。

  • 线程安全方面:饿汉式线程安全 (在线程还没出现之前就已经实例化了,因此饿汉式线程一定是安全的)。懒汉式线程不安全( 因为懒汉式加载是在使用时才会去new 实例的,那么你去new的时候是一个动态的过程,是放到方法中实现的,如果这个时候有多个线程访问这个实例,这个时候实例还不存在,还在new,就会进入到方法中,有多少线程就会new出多少个实例。一个方法只能return一个实例,那最终return出哪个呢?是不是会覆盖很多new的实例?这种情况当然也可以解决,那就是加同步锁,避免这种情况发生) 。

  • 执行效率上:饿汉式没有加任何的锁,因此执行效率比较高。懒汉式一般使用都会加同步锁,效率比饿汉式差。

  • 性能上:饿汉式在类加载的时候就初始化,不管是否使用都实例化了,所以会占据空间,浪费内存。懒汉式什么时候需要什么时候实例化,相对来说不浪费内存。

  • C++实现

  • 具体可以看 https://blog.csdn.net/q5707802/article/details/79251148
    具体可以看 https://stackoverflow.com/questions/1008019/c-singleton-design-pattern

Q3 请你说一说OOP(面向对象编程)的设计模式的五项原则

  1. 单一职责原则
    单一职责有2个含义,一个是避免相同的职责分散到不同的类中,另一个是避免一个类承担太多职责。减少类的耦合,提高类的复用性。

  2. 接口隔离原则
    表明客户端不应该被强迫实现一些他们不会使用的接口,应该把胖接口中额方法分组,然后用多个接口代替它,每个接口服务于一个子模块。简单说,就是使用多个专门的接口比使用单个接口好很多。
    该原则观点如下:
    1)一个类对另外一个类的依赖性应当是建立在最小的接口上
    2)客户端程序不应该依赖它不需要的接口方法。

  3. 开放-封闭原则
    open模块的行为必须是开放的、支持扩展的,而不是僵化的。
    closed在对模块的功能进行扩展时,不应该影响或大规模影响已有的程序模块。一句话概括:一个模块在扩展性方面应该是开放的而在更改性方面应该是封闭的。
    核心思想就是对抽象编程,而不对具体编程。

  4. 替换原则
    子类型必须能够替换掉他们的父类型、并出现在父类能够出现的任何地方。
    主要针对继承的设计原则
    1)父类的方法都要在子类中实现或者重写,并且派生类只实现其抽象类中生命的方法,而不应当给出多余的,方法定义或实现。
    2)在客户端程序中只应该使用父类对象而不应当直接使用子类对象,这样可以实现运行期间绑定。

  5. 依赖倒置原则
    上层模块不应该依赖于下层模块,他们共同依赖于一个抽象,即:父类不能依赖子类,他们都要依赖抽象类。
    抽象不能依赖于具体,具体应该要依赖于抽象。

最后

以上就是朴实小兔子为你收集整理的C++面经-设计模式设计模式的全部内容,希望文章能够帮你解决C++面经-设计模式设计模式所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(30)

评论列表共有 0 条评论

立即
投稿
返回
顶部