设计模式常见问题和总结

  1. 设计模式可以分为哪几类,分别有哪些设计模式?(10分)
    设计模式分为有创建型,结构型,和行为型。
    创建型:单例设计模式,工厂设计模式,抽象工厂模式,建造者模式,原型模式
    结构型:代理模式,组合模式,享元模式,适配器模式,桥接模式,门面模式,装饰器模式,
    行为型:委派模式,策略模式,模板方法模式,观察者模式,访问者模式,责任链模式,迭代器模式,中介模式

2.设计模式有哪些设计原则?(10分)
(1)单一职责,一个类只负责一项自己业务,不做其他类的改变操作
(2)开闭原则,对修改关闭,对扩展开放
(3)依赖倒置原则,高层不依赖于细节,细节和高层都依赖抽象。
(4)接口隔离原则, 细化接口分类,避免接口有过多方法兼容过多不同类的方法,尽量抽象。
(5)里氏替换原则,子类不能改变父类方法的逻辑。
(6)迪米特法则,最少知道原则,只负责自己业务线下操作,尽量减少对其他类的依赖。
(7)合成复用原则,尽量使用组合和聚合,减少对继承使用产生的依赖。

3.什么是简单工厂模式、工厂方法模式、抽象工厂模式?(5分)
简单工厂:按照业务需求直接创建所需要的类,简单工厂需要实现接口,按照接口规定内创建相关对象。遵循了依赖倒置原则但违背了单一职责原则。所有构建对象全部由一个工厂完成。
工厂方法:在简单工厂之上进行一次分类升级,每个类型创建都有自己的单独的工厂。但遵循统一的工厂方法且创建不同类型的对象。遵循了单一职责和依赖倒置原则。
抽象工厂方法:在工厂方法之上整改再次升级,不仅仅对产品构建而是针对产品族进行构建,不但可以创建各种产品本身并且可以生产不同类型的产品。增加了一个生产维度更好的进行松耦合,但弊端如果基本抽象接口发生了业务改变,那么所有实现此抽象的抽象方法和产品组抽象类全部发生改变。故此要谨慎使用。

  1. 什么是单例模式,并说出2到3中不同的创建方式以及他们的优缺点?(15分)
    单例模式是保证全局使用同一个对象,保证数据的安全隔离和避免对内存的消耗。单例设计模式创建方法有如下4种:
    (1).饿汉式:从系统初始化时便将对象进行创建完成加载到内存中以备后用,优点是代码简单,没有任何线程安全问题。缺点是容易对内存造成浪费。
    (2).懒汉式:从第一次调用实例化时候进行创建一次,而后所有调用都用第一次创建的对象。优点是对内存浪费情况减轻,缺点会发生线程安全。优化线程安全有双重检查锁和静态内部类两种,第一种对性能消耗大于第二种,故选择第二种偏多。
    (3).枚举式:通过枚举类来进行判断从而单例创建,内部逻辑更像饿汉式,只不过饿汉式直接将指针指向了新的内存地址,而枚举式则在创建初期将所有要实例化的单例存放到了枚举内部的node中,node中的map存储了所有的单例。优点是无法通过反射等手段进行暴力破坏单例,缺点是系统启动时候就将所需要的实例化纳入到了内部的map集合中,也面临内存浪费的情况。,同时代码可读性也低。而后进行了改良便是Spring的IOC容器。
    (4).注册式:容器式存储单例,Spring创建实例容器也是使用的此种,将每次创建的对象存储到集合中,下次再次调用时候直接通过key来进行查找对应的单例。内存消耗上远远小于饿汉式,因内部是concurrntHashMap确保了线程安全性。可维护性和可读性也增强。使用Spring加载容器时默认都为容器的饿汉式加载方式,但也可以通过配置文件修改强制按照懒汉式方式进行加载。前者内存消耗大,但执行效率快,后者内存消耗小,执行效率低于前者。

5.有哪些方式可以破坏单例模式,怎么解决单例破坏?(5分)
破坏单例方式可为反射机制和序列以及反序列化等操作。对于反射机制可通过构造方法中进行单例判断如已存在可直接抛出异常,也可使用枚举单例创建方式从jdk底层杜绝反射破坏。对于反序列化类对象操作可重写Serilazible 中的readResolve()方法,来覆盖原有的判断逻辑解决反序列化带来的单例破坏。

6.什么是浅克隆,什么是深克隆,实现深克隆的方式有哪些?(5分)
浅克隆只是复制基础数据类型,对于引永型会复制原有地址到新对象中。所以浅克隆在修改引用型数据类型时会对原有引用型数据发生改变。
深克隆对于潜克隆力度更大,不仅对基础数据类型,对引用数据类型也一并进行了拷贝并且将指针指向了新的地址让两者的引用数据类型进行独立分割。
实现深克隆方式有三种一种是序列反序列化将对象重新指向内存从而达到深拷贝的效果,还一种是递归调用判断对象是否是引用,从而再次执行克隆达到深克隆目的。还一种是通过fastJson工具对需要克隆的对象转化成byte字节数组进行克隆。

7.实现动态代理的方式有哪些,以及他们的区别?spring用的是哪个代理模式?(20分)
动态代理分为静态代理和动态代理,动态代理又分为jdk实现和cglib实现方式。
静态代理是传统代理模式,需要传入特定被代理的对象,并且手动调用代理方法等。
动态代理一般指的是jdk代理,不用管被代理的对象类型,只要被代理对象实现和代理对象的接口即可。并且可以通过反射方式直接获取相关被代理的方法。
jdk和cglib区别在于jdk通过反射方式调用接口下实现类,代理和被代理对象需要实现抽象接口。由于是反射实现,反射的内部校验机制导致执行速度会慢。但约束性比较强,必须实现接口。
cglib不需要实现接口,它是直接通过反射和Asm框架生成三个不同类,来继承被代理的类重写被代理的方法。由于生成的Fastclass中保存了所有方法的索引,可以直接通过index索引找到对应方法,免去了反射的遍历所有方法方式提高执行效率。但因生成算法比jdk反射复杂故生成时间慢于jdk方式。
Spring默认使用的是jdk形式,如果bean实现了接口则按jdk代理,如果没有则按照cglib生成。当然也可以修改配置文件默认使用cglib方式生成。

8.什么是模板模式,它的作用在哪?(5分)
模板模式,是流程化的一种方法模板,作用在于规范流程,能复用父类的共用方法,减少代码臃肿,可以通过内置钩子方法修改范式逻辑。如jdbc中的创建connection等都是用的模板方法.

9.什么是策略模式?优点缺点在哪?(5分)
封装了算法家族,在同一行为下传入不算法达到不同结果的方案模式。优点是符合开闭原则,避免了许多if else的复杂判断。缺点是调用者必须了解所有策略,并且会有诸多的策略类,增加维护成本。

10.享元模式与注册式单例模式的区别?(5分)
享元模式是结构型,注册式单例为创建型。两者其目的不同,享元模式针对的是对数据模式的反复复用,且有内部状态和外部状态,并非一成不变全部缓存之中,有可变数据。整体是一个对象池,在一定规则内可以调用相同数据的对象,减少对对象的反复创建带来的内存消耗。
注册式单例在乎的是对对象本身的一个创建,确保每个单例都是独立存确保数据的安全性和一致性。容器内存储的所有单例都是独立的个体提供给不同对象使用,无法共用。

11.什么是双亲委派?(5分)
双亲委派是类加载时候用到的机制,原理为层级上传,子类加载时候先上交给父类判断是否存在如果不存在则继续向上报,直到最顶层后判断加载,如果不能加载则下沉到子类加载,如果再不能加载继续下沉直到最下级还不能加载则抛出异常,此方法优点可以确保对象数据的安全性,不会被恶意代码串改。

12.委派模式跟代理模式的区别?(5分)
委派模式更注重的是结果,遵循了迪米特法则,将任务下发后得到想要的结果,而不关心下级是如何实现的。代理关注的是过程,代理类需要封装被代理的方法,从而对方法前后进行一些处理达到代码强化的效果。

13.什么是观察者模式?(5分)
属于订阅-发布,源监听,实现了一对多的依赖关系。指一个元素可以被多个观察者类和对象监听,一旦被观察者发生了改变那么其观察者会自行进行发生改变。

=========================
1、请用自己的语言说出你对享元、组合、适配器、桥接模式的理解
享元模式:就是共享对象池,在面临同一个数据反复创建对象时候可以使用享元模式,享元模式状态分为内部状态和外部状态两种,内部状态是不会发生改变,外部状态会根据周期发生改变。使用享元模式创建对象池从而达到减少对内存的消耗目的。属于结构型设计模式

组合:适用于树形结构形式,观念在于“整体-分支”,两者可以相互依存,同时又能组合到一起成为上下级。主要组成为:抽象节点,树节点和叶子节点。实现模式分为透明组合模式和安全组合模式,透明组合模式在初创抽象类时候可以尽可能想到的方法全部加入,并且继承类全部共享方法,适合上下级行为动作相同的设计。安全组合模式主要针对上下级有诸多不同之处,下级需要定制不同自由行为的设计模式。

适配器:适配器模式主要针对接口不匹配导致无法一起工作的两个类能进行并存工作。适配器实现构成有:目标角色,源角色,适配器三者组成。实现方式有类适配器,对象适配器和接口适配器,三者前两者针对类本身和传入对象本身的兼容,第三者则更为兼容。拥有诸多兼容方法,不限定某一兼容方法,但会出现许多空的实现方法,代码略显臃肿。属于结构型设计模式

桥接模式:独立分离了抽象接口和具体实现类,让两者独立扩展,从而又相互依存。主要构成:抽象(Abstraction),修正抽象(RefinedAbstraction) ,实现(Implementor),具体实现(Concreteimplementor),因为没有用多继承,选用组合,从而遵循了开闭原则和里氏替换原则和依赖倒置原则,是个非常不错的设计模式。缺点是逻辑过于抽象不易理解。
2、请说出享元与单例模式的区别
享元模式和单例模式的容器单例非常相像,但两者角度不同,单例模式只是创建唯一对象,确保请求对象在内存中唯一。享元模式只是对象池对内部资源可以复用,外部资源发生改变时还是要创建新对象。单例模式针对类本身,只要是对象就要唯一,而享元模式则是关注逻辑的角度针对对象内元素的复用。

1.委派模式与代理模式区别在哪?委派模式与策略模式区别?
委派模式针对职责,具体业务由具体人员实现,遵循了单一职责和迪米特法则。是行为型模式,代理是结构型模式,针对行为的结果,对行为的过程进行增强处理。但委派模式没有对行为本身进行改变。
委派模式是谁来做,有分配层级。策略模式是那种方式做,属平行同一级别执行。

2.什么是双亲委派,双亲委派优势在哪?
双亲委派在类加载过程中有使用,其意思是类加载器加载类的时候会先判断类是否加载过,如果没有加载过就向上级判断,直到顶层的bootStrapClassLoader,判断当前类可否加载如果可以加载直接加载,如果不能加载就下放下级加载,直到最下级依旧不能加载则抛出classNotFound错误。双亲委派优势在于保证class类不被非法程序窜改,就算窜改了也不能加载因为,就算加载了也不是原来的对象。保证了数据的操作安全。

3.什么是模板方法模式,它的优点在哪里?
模板方法模式是一种行为型模式,定义算法后由子类进行算法实现的一种设计模式。优点在于提取公共方法的复用和顺序规范。

4.什么是责任链模式?
属于行为型模式的一种。由多个单元执行各自任务最后组合一起完成所有逻辑的链式设计模式,每个单元执行完自己的方法判断后通过则下放到下一级单元执行,直到代码结束。优点在于易于扩展请求类,直接在链式中增加也删减逻辑判断即可,缺点是如责任链过长会影响性能,并且存在循环引用时会造成死循环,导致系统崩塌。

1.用自己的语言总结什么是创建型模式,什么是结构型模式,什么是行为型模式?举例哪些设计模式是创建型,哪些是结构型,哪些是行为型
创建型设计模式针对类的创建,以各种标准和手段达到不同形式的创建类的目的。结构型模式针对方法执行中,对方法本身梳理修饰和包装增强等。行为型模式针对结果,以不同角度来执行最终达到方法结束的目的。创建型主要分为单例,工厂,原型,建造者等。结构型为代理,享元,适配器等。行为型有委派,组合,策略,状态,模板方法等。
2.单例写法有哪些,各自有哪些特点问题?
单例有饿汉,懒汉,枚举,注册。饿汉对内存消耗大,但无线程安全问题。懒汉有线程问题但对内存开销相比饿汉更为节省,能被反射和序列反序列破解单例,枚举式无法被单例破解。注册式单例性能优于传统利用锁和内部加载累处理饿汉式效率高,同时更加灵活。
3.什么是代理模式,有几种代理模式,区别在哪?
代理模式是做一些预处理和后处理的手段达到对核心方法的一个强化,同时安全隔离核心操作。代理模式分为静态代理动态代理,动态又分为jdk和cglib的代理模式,区别在于静态代理针对传入的被代理对象和代理方法都是手动操作执行,动态代理可以不知道什么方法和类直接自动执行。jdk通过反射调用接口下的实现类,cglib是通过asm框架创建新的类继承被代理类并且通过索引能快速定位方法位置避免全局遍历方法查找,所以执行速度高于jdk.但因创建过程繁琐,创建过程时间比jdk要长。
4.深克隆有哪几种方法?
可以通过序列化反序列让所有参数指针指向新地址,也可以通过内部迭代实现深克隆模式。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值