当前位置 博文首页 > 程序员springmeng:??设计模式肝完了,还挺全!腾讯和阿里的offe

    程序员springmeng:??设计模式肝完了,还挺全!腾讯和阿里的offe

    作者:[db:作者] 时间:2021-08-29 16:18

    设计模式肝完了,还挺全!腾讯和阿里的offer已拿!

    金九银十已经来了,挺近大厂最好的机会已经来了!如果你是要找工作的,一定要抓住这个机会!

    前面已经整理了很多的面试资料:

    1,??爆肝!整理了一周的Spring面试大全【含答案】,吊打Java面试官【建议收藏】!??

    2,??肝完了,一天掌握数据结构和算法面试题,吊打面试官,建议收藏??

    3,??集合很简单?开什么玩笑?肝了一周,全是精华,万字讲解!面试再不怕集合问题了!!!??

    4,肝完了,总结了SpringBoot与缓存的知识点,快速掌握

    5,Mysql面试大全,看完可以吊打面试官!!!

    6,入计算机专业的师弟师妹,别再迷茫了,我整理一份CS的学习路线大全!帮你超越大部分的同学!

    7,??专科出身拿到阿里offer,小孟直呼666!【付硬核面试】??

    前面一个小伙伴准备非常充分,已经拿到了阿里的和腾讯的offer,通过和他聊面经,我发现设计模式被面的概率基本是100%。

    ?

    ?上次投票,在大厂的同学挺多啊,欢迎给我面经,质量搞,我可以付费,为价值买单,帮助你我他!

    废话多不多,直接开干!

    目录

    Q1:设计模式有多少种?

    Q2:设计模式有哪些原则?

    Q3:设计模式的分类,你知道哪些设计模式?

    Q4:说?说简单??模式

    Q5:说?说???法模式

    Q6:Spring 框架中都用到了哪些设计模式?

    Q7:抽象??模式了解吗?

    Q8:单例模式的特点是什么?

    Q9:单例模式有哪些实现?

    Q10:讲?讲代理模式

    Q11:讲?讲装饰器模式

    Q12:装饰器模式和动态代理的区别?

    Q13:讲?讲适配器模式

    Q14:适配器模式和和装饰器模式以及代理模式的区别?

    Q15:讲?讲策略模式

    Q16:讲?讲模板模式

    Q17:讲?讲观察者模式


    有的时候会问设计模式基本的概念,有的时候会问设计模式具体的内容或者让你手画图,有的时候会问框架用到了那些设计模式!

    Q1:设计模式有多少种?

    设计模式一般分为23种。

    创建型模式:

    工厂方法模式(Factory Method)

    抽象工厂模式(Abstract Factory)

    单例模式(Singleton)

    建造者模式(Builder)

    原型模式(Prototype)

    结构型模式:

    适配器模式(Adapter)

    装饰器模式(Decorator)

    代理模式(Proxy)

    外观模式(Facade)

    桥接模式(Bridge)

    组合模式(Composite)

    享元模式(Flyweight)

    行为型模式:

    策略模式(Strategy)

    模板方法模式(Template Method)

    观察者模式(Observer)

    迭代器模式(Iterator)

    责任链模式(Chain of Responsibility)

    命令模式(Command)

    备忘录模式(Memento)

    状态模式(State)

    访问者模式(Visitor)

    中介者模式(Mediator)

    解释器模式(Interpreter)

    Q2:设计模式有哪些原则?

    通常来说设计模式的原则有依赖导致原则、单一职责原则、接口隔离原则、开闭原则、迪米特法原则、里氏替换原则。设计模式原则图如下所示:

    Q3:设计模式的分类,你知道哪些设计模式?

    创建型: 在创建对象的同时隐藏创建逻辑,不使? new 直接实例化对象,程序在判断需要创建哪些对象时更灵活。包括工厂/抽象工厂/单例/建造者/原型模式。

    结构型: 通过类和接?间的继承和引?实现创建复杂结构的对象。包括适配器/桥接模式/过滤器/组合/ 装饰器/外观/享元/代理模式。

    行为型: 通过类之间不同通信方式实现不同行为。包括责任链/命名/解释器/迭代器/中介者/备忘录/观察者/状态/策略/模板/访问者模式。

    分类图如下所示:

    ?

    Q4:说?说简单??模式

    简单工厂模式指由?个工厂对象来创建实例,客户端不需要关注创建逻辑,只需提供传?工厂的参数。

    适?于工厂类负责创建对象较少的情况,缺点是如果要增加新产品,就需要修改工厂类的判断逻辑,违背开闭原则,且产品多的话会使工厂类?较复杂。

    Calendar 抽象类的?历对象。方法,调?方法根据不同的地区参数创建不同的Spring 中的 BeanFactory 使?简单工厂模式,根据传??个唯?的标识来获得 Bean 对象。

    简单的实例:

    /**
    
    ?* 拿铁、美式咖啡、卡布奇诺等均为咖啡家族的一种产品
    
    ?* 咖啡则作为一种抽象概念
    
    ?* @author 
    
    ?*/
    
    public abstract class Coffee {
    
    ??? /**
    
    ???? * 获取coffee名称
    
    ???? * @return
    
    ???? */
    
    ??? public abstract String getName();
    
    }
    
    
    /**
    
    ?* 美式咖啡
    
    ?* @author Lsj
    
    ?*
    
    ?*/
    
    public class Americano extends Coffee {
    
    
    ??? @Override
    
    ??? public String getName() {
    
    ??????? return "美式咖啡";
    ??? }
    
    }
    
    
    /**
    
    ?* 卡布奇诺
    
    ?* @author Lsj
    
    ?*/
    
    public class Cappuccino extends Coffee {
    
    
    ??? @Override
    
    ??? public String getName() {
    
    ??????? return "卡布奇诺";
    
    ??? }
    
    }
    
    
    /**
    
    ?* 拿铁
    
    ?* @author Lsj
    
    ?*/
    
    public class Latte extends Coffee {
    
    ??? @Override
    
    ??? public String getName() {
    
    ??????? return "拿铁";
    ??? }
    
    }

    Q5:说?说???法模式

    工厂方法模式指定义?个创建对象的接?,让接?的实现类决定创建哪种对象,让类的实例化推迟到?类中进行。

    客户端只需关?对应工厂而无需关?创建细节,主要解决了产品扩展的问题,在简单??模式中如果产品种类变多,工厂的职责会越来越多,不便于维护。

    Collection 接?这个抽象工厂中定义了?个抽象的 工厂方法,返回?个 Iterator 类的抽象产

    品。该?法通过 ArrayList 、HashMap 等具体工厂实现,返回 Itr、KeyIterator 等具体产品。

    Spring 的 FactoryBean 接?的?法也是工厂方法。

    Q6:Spring 框架中都用到了哪些设计模式?

    Spring 框架中使用到了大量的设计模式,下面列举了比较有代表性的:

    1. 代理模式—在 AOP 和 remoting 中被用的比较多。

    2. 单例模式—在 spring 配置文件中定义的 bean 默认为单例模式。

    3. 前端控制器—Spring 提供了 DispatcherServlet 来对请求进行分发。

    Q7:抽象??模式了解吗?

    抽象工厂模式指提供?个创建?系列相关或相互依赖对象的接?,?需指定它们的具体类。

    客户端不依赖于产品类实例如何被创建和实现的细节,主要?于系统的产品有多于?个的产品族,?系 统只消费其中某?个产品族产品的情况。抽象工厂模式的缺点是不方便扩展产品族,并且增加了系统的 抽象性和理解难度。

    java.sql.Connection 接?就是?个抽象工厂,其中包括很多抽象产品如 Statement、Blob、Savepoint等。

    public class AbstractFactoryTest {
    
    ?? public static void main(String[] args) {
    
    ?????? // 抽象工厂
    
    ?????? String result = (new CoffeeFactory()).createProduct("Latte");
    
    ?????? System.out.println(result); // output:拿铁
    
    ?? }
    
    }
    
    // 抽象工厂
    
    abstract class AbstractFactory{
    
    ?? public abstract String createProduct(String product);
    
    }
    
    // 啤酒工厂
    
    class BeerFactory extends AbstractFactory{
    
    ?? @Override
    
    ?? public String createProduct(String product) {
    
    ?????? String result = null;
    
    ?????? switch (product) {
    
    ?????????? case "Hans":
    
    ?????????????? result = "汉斯";
    
    ?????????????? break;
    
    ?????????? case "Yanjing":
    
    ?????????????? result = "燕京";
    
    ?????????????? break;
    
    ?????????? default:
    
    ?????????????? result = "其他啤酒";
    
    ?????????????? break;
    
    ?????? }
    
    ?????? return result;
    
    ?? }
    
    }
    
    /\* \* 咖啡工厂 \*/
    
    class CoffeeFactory extends AbstractFactory{
    
    ?? @Override
    
    ?? public String createProduct(String product) {
    
    ?????? String result = null;
    
    ?????? switch (product) {
    
    ?????????? case "Mocca":
    
    ?????????????? result = "摩卡";
    
    ?????????????? break;
    
    ?????????? case "Latte":
    
    ?????????????? result = "拿铁";
    
    ????? ?????????break;
    
    ?????????? default:
    
    ?????????????? result = "其他咖啡";
    
    ?????????????? break;
    
    ?????? }
    
    ?????? return result;
    
    ?? }
    
    }

    Q8:单例模式的特点是什么?

    单例模式属于创建型模式,?个单例类在任何情况下都只存在?个实例,构造方法必须是私有的、由自己创建?个静态变量存储实例,对外提供?个静态公有方法获取实例。

    优点是内存中只有?个实例,减少了开销,尤其是频繁创建和销毁实例的情况下并且可以避免对资源的多重用。缺点是没有抽象层,难以扩展,与单?职责原则冲突。

    Spring 的 ApplicationContext 创建的 Bean 实例都是单例对象,还有 ServletContext、数据库连接池等也都是单例模式。

    UML类图如下所示:

    ?

    单例模式举例实现:

    1 class Person{
    
    ?2 private:
    
    ?3???? Person(){};
    
    ?4???? Person(const Person&){};
    
    ?5
    
    ?6???? static Person *Singleton; //静态变量,类内声明,类外初始化, 初始化时不用static,需指定作用域
    
    ?7
    
    ?8 public:
    
    ?9???? static Person *getInstance(){
    
    10???????? return Singleton;
    
    11???? }
    
    12 };
    
    13
    
    14 Person *Person::Singleton = new Person;
    
    15
    
    16 void test01(){
    
    17
    
    18???? Person::getInstance();//外部通过接口访问单例
    
    19???? Person *p = Person::getInstance();
    
    20???? Person *p1 = Person::getInstance();
    
    21
    
    22???? //--------------
    
    23???? //不能直接定义或new实例,只能通过调用接口
    
    24???? //Person p2;
    
    25???? //Person *p1 = new(*p); //这里调用拷贝构造函数
    
    26???? //--------------
    
    27
    
    28???? if (p == p1){
    
    29???????? cout << "两个单例的地址相同,为同一个单例" << endl;
    
    30???? }
    
    31
    
    32 }

    Q9:单例模式有哪些实现?

    饿汉式:在类加载时就初始化创建单例对象,线程安全,但不管是否使?都创建对象可能会浪费内存。

    懒汉式:在外部调?时才会加载,线程不安全,可以加锁保证线程安全但效率低。

    双重检查锁:使? volatile 以及多重检查来减?锁范围,提升效率。

    静态内部类:同时解决饿汉式的内存浪费问题和懒汉式的线程安全问题。

    枚举:《E?ective Java》提倡的?式,不仅能避免线程安全问题,还能防?反序列化重新创建新的对象,绝对防?多次实例化,也能防?反射破解单例的问题。

    Q10:讲?讲代理模式

    代理模式属于结构型模式,为其他对象提供?种代理以控制对这个对象的访问。优点是可以增强?标对 象的功能,降低代码耦合度,扩展性好。缺点是在客户端和?标对象之间增加代理对象会导致请求处理速度变慢,增加系统复杂度。

    为其他对象提供一种代理以控制对这个对象的访问。在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。

    具体的代理模式的代码如下所示:

    package com.Model.Proxy;
    
    
    
    //买车行为
    
    public interface BuyCar {
    
    ??? public void buycar();
    
    }
    
    
    package com.Model.Proxy;
    
    
    public class People implements BuyCar {
    
    ??? private int cash;
    
    ??? private String vip;
    
    ??? private String username;
    
    ??? @Override
    
    ??? public void buycar() {
    
    ??????? System.out.println(username + " is vip so he/she can buy any car...");
    
    ??? }
    
    
    ??? public int getCash() {
    
    ??????? return cash;
    
    ??? }
    
    
    
    ??? public void setCash(int cash) {
    
    ??????? this.cash = cash;
    
    ??? }
    
    
    ??? public String getVip() {
    
    ??????? return vip;
    
    ??? }
    
    
    ??? public void setVip(String vip) {
    
    ??????? this.vip = vip;
    
    ??? }
    
    
    ??? public String getUsername() {
    
    ??????? return username;
    
    ??? }
    
    
    ??? public void setUsername(String username) {
    
    ??????? this.username = username;
    
    ??? }
    
    
    }
    
    
    // 代理类 去检测买车行为是否符合规则
    
    class ProxyBuyCar implements BuyCar {
    
    ??? private People People;
    
    ??? public People getPeople() {
    
    ??????? return People;
    
    ??? }
    
    ??? public void setPeople(People people) {
    
    ??????? People = people;
    
    ??? }
    
    
    ??? @Override
    
    ??? public void buycar() {
    
    ??????? if (People.getVip().equals("vip")) {
    
    ??????????? People.buycar();
    
    ??????? } else if (People.getCash() >= 50000) {
    
    ??????????? System.out.println(People.getUsername() + "buy a new car trade over...");
    
    ??????? } else {
    
    ??????????? System.out.println(People.getUsername() + "people can't buy a car ");
    
    ??????? }
    
    ??? }
    }

    Spring 利?动态代理实现 AOP,如果 Bean 实现了接?就使? JDK 代理,否则使? CGLib 代理。

    静态代理:代理对象持有被代理对象的引?,调?代理对象?法时也会调?被代理对象的?法,但是会 在被代理对象?法的前后增加其他逻辑。需要?动完成,在程序运?前就已经存在代理类的字节码?件,代理类和被代理类的关系在运?前就已经确定了。 缺点是?个代理类只能为?个?标服务,如果要服务多种类型会增加?作量。

    动态代理:动态代理在程序运?时通过反射创建具体的代理类,代理类和被代理类的关系在运?前是不确定的。动态代理的适?性更强,主要分为 JDK 动态代理和 CGLib 动态代理。

    JDK 动态代理:通过类的?法获取?个动态代理对象,需要传?三个参数,被代理对象的类加载器、被代理对象实现的接?,以及?个器来指明具体的逻辑,相?静态代理的优势是接?中声明的所有?法都被转移到调?处理的?法集中处理。

    CGLib 动态代理:JDK 动态代理要求实现被代理对象的接?,? CGLib 要求继承被代理对象,如果?个类是 ?nal 类则不能使? CGLib 代理。两种代理都在运?期?成字节码,JDK 动态代理直接写字节码,? CGLib 动态代理使? ASM 框架写字节码,ASM 的?的是?成、转换和分析以字节数组表示的已编译 Java 类。 JDK 动态代理调?代理?法通过反射机制实现,? GCLib 动态代理通过 FastClass 机制直接调??法,它为代理类和被代理类各?成?个类,该类为代理类和被代理类的?法分配?个 int 参数,调??法时可以直接定位,因此调?效率更?。

    Q11:讲?讲装饰器模式

    我们首先看下模式的结构图:

    装饰器模式属于结构型模式,在不改变原有对象的基础上将功能附加到对象,相?继承可以更加灵活地 扩展原有对象的功能。

    装饰器模式适合的场景:在不想增加很多?类的前提下扩展?个类的功能。

    java.io 包中,InputStream 字节输?流通过装饰器 Bu?eredInputStream 增强为缓冲字节输?流。

    Q12:装饰器模式和动态代理的区别?

    首先我们看一下他们的类图:

    ?

    装饰器模式的关注点在于给对象动态添加?法,?动态代理更注重对象的访问控制。动态代理通常会在 代理类中创建被代理对象的实例,?装饰器模式会将装饰者作为构造?法的参数。

    Q13:讲?讲适配器模式

    适配器模式属于结构型模式,它作为两个不兼容接?之间的桥梁,结合了两个独?接?的功能,将?个 类的接?转换成另外?个接?使得原本由于接?不兼容?不能?起?作的类可以?起?作。

    缺点是过多使?适配器会让系统?常混乱,不易整体把握。

    java.io 包中,InputStream 字节输?流通过适配器 InputStreamReader 转换为 Reader 字符输?流。

    Spring MVC 中的 HandlerAdapter,由于 handler 有很多种形式,包括 Controller、HttpRequestHandler、Servlet 等,但调用方式?是确定的,因此需要适配器来进?处理,根据适配规则调? handle 方法。

    Arrays.asList ?法,将数组转换为对应的集合(注意不能使?修改集合的?法,因为返回的 ArrayList是 Arrays 的?个内部类)。

    适配器实现的代码如下:

    /\* \* 传统的充电线 MicroUSB \*/
    
    interface MicroUSB {
    
    ??? void charger();
    
    }
    
    /\* \* TypeC 充电口 \*/
    
    interface ITypeC {
    
    ??? void charger();
    
    }
    
    class TypeC implements ITypeC {
    
    ? ??@Override
    
    ??? public void charger() {
    
    ??????? System.out.println("TypeC 充电");
    
    ??? }
    
    }
    
    /\* \* 适配器 \*/
    
    class AdapterMicroUSB implements MicroUSB {
    
    ??? private TypeC typeC;
    
    ??? public AdapterMicroUSB(TypeC typeC) {
    
    ??????? this.typeC = typeC;
    
    ??? }
    
    ??? @Override
    
    ??? public void charger() {
    
    ??????? typeC.charger();
    
    ??? }
    
    }
    
    /\* \* 测试调用 \*/
    
    public class AdapterTest {
    
    ??? public static void main(String[] args) {
    
    ??????? TypeC typeC = new TypeC();
    
    ??????? MicroUSB microUSB = new AdapterMicroUSB(typeC);
    
    ? ??????microUSB.charger();
    
    ??? }
    
    }

    Q14:适配器模式和和装饰器模式以及代理模式的区别?

    适配器模式没有层级关系,适配器和被适配者没有必然连续,满? has-a 的关系,解决不兼容的问题, 是?种后置考虑。

    装饰器模式具有层级关系,装饰器与被装饰者实现同?个接?,满? is-a 的关系,注重覆盖和扩展,是?种前置考虑。

    适配器模式主要改变所考虑对象的接?,?代理模式不能改变所代理类的接?。

    Q15:讲?讲策略模式

    策略模式属行为模型模式,定义了?系列算法并封装起来,之间可以互相替换。策略模式主要解决在有多种算法相似的情况下,使? if/else 所带来的难以维护。

    优点是算法可以?由切换,可以避免使用多重条件判断并且扩展性良好,缺点是策略类会增多并且所有 策略类都需要对外暴露。

    在集合框架中,经常需要通过构造方法传??个比较器 Comparator 进行比较排序。Comparator 就是

    ?个抽象策略,?个类通过实现该接?并重写 compare 方法成为具体策略类。

    创建线程池时,需要传?拒绝策略,当创建新线程使当前运?的线程数超过 maximumPoolSize 时会使?相应的拒绝策略处理。

    策略模式实现的代码如下所示:

    
    /\* \* 声明旅行 \*/
    
    interface ITrip {
    
    ??? void going();
    
    }
    
    class Bike implements ITrip {
    
    ??? @Override
    
    ??? public void going() {
    
    ??????? System.out.println("骑自行车");
    
    ??? }
    
    }
    
    class Drive implements ITrip {
    
    ??? @Override
    
    ??? public void going() {
    
    ??????? System.out.println("开车");
    
    ??? }
    
    }
    
    /\* \* 定义出行类 \*/
    
    class Trip {
    
    ??? private ITrip trip;
    
    
    
    ??? public Trip(ITrip trip) {
    
    ??????? this.trip = trip;
    
    ??? }
    
    
    
    ??? public void doTrip() {
    
    ??????? this.trip.going();
    
    ??? }
    
    }
    
    /\* \* 执行方法 \*/
    
    public class StrategyTest {
    
    ??? public static void main(String[] args) {
    
    ??????? Trip trip = new Trip(new Bike());
    
    ??????? trip.doTrip();
    
    ??? }
    
    }

    程序执行的结果: 骑自行车

    Q16:讲?讲模板模式

    模板模式属于?为型模式,使?类可以在不改变算法结构的情况下重新定义算法的某些步骤,适?于抽 取?类重复代码到公共?类。

    优点是可以封装固定不变的部分,扩展可变的部分。缺点是每?个不同实现都需要?个?类维护,会增 加类的数量。

    为防?恶意操作,?般模板?法都以 ?nal 修饰。

    HttpServlet 定义了?套处理 HTTP 请求的模板,service ?法为模板?法,定义了处理HTTP请求的基本流程,doXXX 等?法为基本?法,根据请求?法的类型做相应的处理,?类可重写这些?法。