设计模式见解

1、在java中,什么时候用重载,什么使用用重写?

重载(Overloading)和重写(Overriding)都可以对业务功能的增强。

重载: 在同一个类中,方法名一样,但是参数不一样(即参数的数量或参数类型不能完全相同)

重写: 在父子类中,子类重写了父类中的方法。需要具有相同的方法名、参数、返回值。

重载 就是在类中可以创建多个方法,它们具有相同的名字,但具有不同的参数和不同的定义。

调用方法时通过传递给它们的不同参数个数和参数类型来决定具体使用哪个方法, 这就是多态性。

重载中返回值类型可以相同也可以不相同。无法以返回型别作为重载函数的区分标准。

重写 中访问修饰符的限制一定要大于被重写方法的访问修饰(public>protected>default>private)

被final修饰和private修饰的方法不能被重写

代码中应用: 重载:之前写的登录,在系统内是loginname和password两个参数才能登录,但是因为业务需要跟第三方对接接口的时候,可以从他们系统直接登录到我们系统,但是没有loginname和password,只有根据双方系统中都有的一个字段身份证来认证,我处理方法:根据第三方传来的身份证号生成token并且返回,他们带着token再次来请求。所以我要写一个login()的重载方法。跟之前的参数不一致,只需一个参数token就可以。 重写: 平时和同事写一个类似的功能,所需参数一样,返回值也一样。就仅仅是业务处理可能不一样,我们就会在父类中写声明一个方法,然后我俩同时重写这个方法,然后各自写自己的业务就行。

2、举例一个你更倾向于抽象类,而不是接口的代码设计场景

抽象类和接口都是对事物的一种抽象, 接口是对动作的一种抽象,而实现类是对根源的抽象。

接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。

抽象方法要被实现,所以不能是静态的,也不能是私有的。

接口可继承接口,并可多继承接口,但类只能单根继承。

当业务中,有一些功能是一致的,大多时候都不会被重写的,这时候可以使用抽象类定义一个具体的实现方法,这样就不用子类一一实现了。例如在spring中的JDBCtemplate中就使用了抽象类作为模板设计模式基础。

 

3、在java中,为什么不允许静态方法中访问非静态变量?

静态方法只能调用静态方法或者变量,非静态方法只能调用非静态方法或者变量。

一个类的静态变量和静态方法是属于这个类本身的,在类被加载的时候就会分配内存(方法区),可以直接通过类名点的方式来调用, 而非静态方法和变量是属于对象的,也只有在外部使用这个类的对象时,比如 new 这个对象时, 非静态变量和方法才会被加载到堆内存中。

所以说,静态变量和方法是优先加载的,而且只加载一次,非静态变量和方法是外部使用的时候才被加载。 所以当静态变量和方法加载后, 非静态变量和方法可能没有被加载,所以不能访问。

在开发中我们会使用很多工具类,在写工具类的时候我们一般都使用的是静态方法,因为不用每次调用的时候都要去new 出来,不用频繁的读写内存, 而是从内存中直接取出来。

4、列举你说了解的软件分层场景,软件分层有哪些好处?

举例: 就像我们在开发中会将代码分为3层,

表现层(controller) 与前端交互数据。

业务层(service) 处理业务

持久层(dao) 与数据库交互,一般写sql

这样分层可以使编写代码的时候各行其志,我们在各自的分层中写对应的代码。

经典的MVC架构:

模型(model)、视图(view)、控制器(controller)。

模型: 关注数据的处理,主要负责业务代码和数据操作。

视图: 页面。 显示数据用的,例如 html 、jsp等。

控制器: 用于 视图和模型 之间的协调

好处: 1、让代码看起来更加清晰。可维护性高。

2、模型和视图之间的耦合性低。

5、请列举符合开闭原则的设计模式。

先说一下开闭原则: 一个软件实体应当对外扩展开放,对修改关闭。 即软件实体应尽量在不修改原有的代码情况下进行扩展。

1、适配器模式: 在适配器模式中,我们通过增加一个新的适配器类来解决接口不兼容的问题,使得原本没有任何关系的类可以协同工作。适配器类继承了目标抽象类,而适配器又有适配者的引用。

2、装饰者设计模式: 装饰者设计模式的本意就是不改变一个对象本身功能的基础上给对象增加额外的新行为。 装饰模式是一种用于替代继承的技术,在装饰模式中引入了装饰类,在装饰类中既可以调用待装饰的原有类的方法,还可以增加新的方法,以扩充原有类的功能

3、工厂方法模式:工厂方法模式引用了 抽象工厂角色。 这样在我们添加具体的产品工厂的时候,只需要继承或实现抽象工厂就行,不用修改原有代码。

4、观察者模式: 定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者模式的别名包括发布-订阅。 当我们需要增加一个具体的观察者时候,不需要修改原有的代码, 而是只需要继承之前定义的观察者接口即可。

5、代理模式: 代理模式分为JDK动态代理和cgLib动态代理, 代理模式是给某一个对象提供一个代理或占位符,并由代理对象来控制对原对象的访问。我们要增强某个方法的时候,只需要在代理类都完成就行,不用在原有代码上做修改。

6、策略模式: 实现某一个功能有多条途径,每一条途径对应一种算法,此时我们可以使用策略模式来实现灵活地选择解决途径。 我们在使用策略模式的时候可以在不修改代码的情况下 增加新的策略方式。

7、模板方法模式: 模板方法模式是一种基于继承的代码复用技术。 在父类中提供了一个定义算法框架的模板方法,还提供了一系列抽象方法、具体方法和钩子方法。 我们可以通过添加不同的子类,来完善我们的需求。但是这样有个不好的地方,就是会导致我们的子类越来越多。

6.总结设计模式中创建型、结构型、行为型之间的根本区别?

创建型

创建型模式与对象的创建有关。

结构型

结构型模式处理类或对象的组合,它采用继承机制来组合接口或实现(类结构型模式),或者通过组合一些对象,从而实现新的功能(对象结构型模式)

行为型

行为型模式对类或对象怎样交互和怎样分配职责进行描述

模式 创建型模式 结构型模式 行为型模式
概念 创建型模式:就是创建对象的模式,抽象了实例化的过程。也可以理解为将创建的对象的过程进行了封装,作为使用者仅仅知道怎么样去使用对象,而不会关心创建对象过程的逻辑 结构型模式是为了解决怎么样组装现有的类,设计它们的交互方式,从而达到实现功能的目的。 行为型模式是对类或者对象进行交互的描述,
包含的设计模式 1、简单工厂模式 2、工厂方法模式 3、抽象工厂模式 4、单例模式 5、原型模式 6、建造者模式 1、适配器模式 2、桥接模式 3.组合模式 4、装饰模式 5、外观模式 6、享元模式 7、代理模式 1、责任链模式 2、命令模式 3、解释器模式 4、迭代器模式 5、中介者模式 6、备忘录模式 7、观察者模式 8、状态模式 9.策略模式 10、模板方法模式 11访问者模式

7、在构造方法中抛出异常是阻止反射破坏单例的唯一方法嘛? 为什么?

不是。在构造方法中抛出异常可以阻止反射破坏单例。因为反射可以获取到私有的构造方法,这样就会根据构造来创建对象,破坏单例,所以在构造方法中抛出异常可以阻止反射破坏单例。如代码:

// 构造私有化
    private LazyInnerClassSingleton(){
        //防止反射破坏单例
        if (InnerClass.lazyInnerClassSingleton != null){
            throw new RuntimeException("不允许创建多个实例");
        }
    }

当然还有其他的方式可以阻止反射破坏单例。 枚举(注册式单例)可以。枚举是jdk1.5之后出现的。

所有的枚举编译后都继承了Enum(抽象类)

设计模式见解

设计模式见解

在JDK源码中我们可以看到反射的 Constructor的 newInstance()的代码反射在通过newInstance创建对象时,会检查该类是否ENUM修饰,如果是则抛出异常,反射失败。

8、双重检查锁为何要做两次非空检测?

第一个判断主要是为了做性能优化,第二个判断是做逻辑控制的。

 /**
    * @Param: []
    * @return: com.gitee.spring.singleton.lazy.LazyDoubleCheckSingleton
    * @Date: 2019/3/13
    * @Description:  doublecheck来解决
    */
    public static LazyDoubleCheckSingleton getInstance2(){
        //线程过来后先判断是否已经生成了对象,如果生成了直接返回,如果没有,线程才会去争抢锁
        if (lazyDoubleCheckSingleton == null){
            synchronized (LazyDoubleCheckSingleton.class){
                // synchronized 只是锁了这一小部分代码。
                //这里加判断是因为,假设有两个线程。A、B 如果A现货的锁运行这段代码,然后会生成
                //对象。接下来释放锁,然后线程B获得锁,此时该类已经生成过对象了,如果没有判断这时候
                //这时候B也会生成新的对象,则会不符合单例原则,所以需要加判断,如果已经有了对象B线程
                //直接返回。
                if (lazyDoubleCheckSingleton == null)
                lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton();
            }
        }
        return lazyDoubleCheckSingleton;
    }

9、原型模式能够给你解决的最大的麻烦是什么?

在之前学设计模式的时候,我们都知道原型模式是一种创建型模式。通过copy这些原型来创建新的对象。

原型模式原理: 是通过克隆的方式创建一个全新的对象,全新的对象在内存中有新的地址,通常对克隆所产生的对象进行修改对原型对象不会造成任何影响,每一个克隆对象都是相互独立的。通过不同的方式修改可以得到一系列相似但不完全相同的对象。

说到克隆又分为两种: 浅克隆和深克隆。

浅克隆

在浅克隆中如果原型对象中的成员变量是基本数据类型的话,将直接复制一份给新的克隆对象。 但是如果成员变量是引用数据类型的话, 是会将引用对象在内存中的地址复制一份给新的克隆对象。Object中clone()方法就是浅拷贝。 注意: 需要注意的是能够实现克隆的Java类必须实现一个标识接口Cloneable,表示这个Java类支持被复制。如果一个类没有实现这个接口但是调用了clone()方法,Java编译器将抛出一个CloneNotSupportedException异常

深克隆

在深克隆中无论原型对象中的成员变量是基本数据类型还是引用数据类型。都将复制一份给新的克隆对象。在代码中我们可以通过实现序列来完成深克隆(Serializable),---> 通过序列化实现的拷贝不仅可以复制对象本身,而且可以复制其引用的成员对象,因此通过序列化将对象写到一个流中,再从流里将其读出来,可以实现深克隆。

在代码中使用

在写代码中,碰到过要将一个对象传递给另一个对象, 这两个对象是一个类的实例化。 之前我是通过先new出来一个新对象然后通过get()、set()。将旧对象的值复制给新的对象,如果用原型模式的话,可以省去很多set()、get()。使用Beanutils 作为浅拷贝。使用Serializable序列化实现深拷贝。

10、简单介绍一下工厂模式,并描述他们各自的优劣以及使用场景?

工厂模式(创建型模式)分为3种:简单工厂模式、工厂方法模式、抽象工厂模式。

简单工厂模式:

优点:1、工厂类中包含了必要的判断逻辑,可以决定在什么时候创建哪一个产品类的对象。而客户端可以不用管对象(实例)的创建。实现了对象的创建与使用的分离。2、客户端不需要知道要使用的实例的具体类型,只需要知道具体的产品类对应的参数即可。

缺点:1、工厂类中有很多 创建实例的逻辑代码,一旦不能正常工作,整个系统都会受到影响。2、使用简单工厂模式肯定会出现很多工厂类,会增加系统的复杂度。

适用场景:工厂类负责创建的对象比较少,由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂

工厂方法模式:

优点:1、基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。它能够让工厂可以自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部。工厂方法模式之所以又被称为多态工厂模式,就正是因为所有的具体工厂类都具有同一抽象父类。2、使用工厂方法模式的另一个优点是在系统中加入新产品时,无须修改抽象工厂和抽象产品提供的接口,无须修改客户端,也无须修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就可以了,这样,系统的可扩展性也就变得非常好,完全符合“开闭原则”。

缺点:1、在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度。

使用场景:客户端不知道它所需要的对象的类。在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建,可将具体工厂类的类名存储在配置文件或数据库中。

抽象工厂模式:

抽象工厂模式与工厂方法模式最大的区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式需要面对多个产品等级结构,一个工厂等级结构可以负责多个不同产品等级结构中的产品对象的创建。

优点:1、但由于工厂方法模式中的每个工厂只生产一类产品,可能会导致系统中存在大量的工厂类,势必会增加系统的开销。此时,我们可以考虑将一些相关的产品组成一个“产品族”,由同一个工厂来统一生产,这个就是抽象工厂模式的思想。

11、如何使用最精简的语句描述产品等级结构和产品族?

产品等级结构产品等级结构即产品的继承结构。 如一个抽象类是电视机,其子类有海尔电视机、海信电视机、TCL电视机,则抽象电视机与具体品牌的电视机之间构成了一个产品等级结构,抽象电视机是父类,而具体品牌的电视机是其子类。

产品族:在抽象工厂中, 产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品。如海尔电器工厂生产的海尔电视机、海尔电冰箱,海尔电视机位于电视机产品等级结构中,海尔电冰箱位于电冰箱产品等级结构中,海尔电视机、海尔电冰箱构成了一个产品族。

   (1) 增加产品族:对于增加新的产品族,抽象工厂模式很好地支持了“开闭原则”,只需要增加具体产品并对应增加一个新的具体工厂,对已有代码无须做任何修改。
​
   (2) 增加新的产品等级结构:对于增加新的产品等级结构,需要修改所有的工厂角色,包括抽象工厂类,在所有的工厂类中都需要增加生产新产品的方法,违背了“开闭原则”。

12、实现代理模式的底层逻辑是什么?

设计模式见解

代理模式概念

给某一个对象提供一个代理或占位符,并由代理对象来控制对原对象的访问。 属于结构型模式

代理模式:包含了 代理类、真实类。代理对象需要含有真实类的引用, 底层逻辑其实就是字节码重组

静态代理

写一个增强类实现 被增强类实现的所有接口,需要把被增强类的引用获取到

JDK动态代理

前提条件:

①必须知道要增强的接口

②必须用Proxy.newProxyInstance创建代理对象

③动态代理只能增强接口中定义的方法

动态代理实现原理: 用动态代理其实是重新生成了一个代理类, 这个代理类和原类 实现了同样的接口。

CGLIB动态代理

CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法(继承)

CGLib 动态代理执行代理方法效率之所以比 JDK 的高是因为 Cglib 采用了 FastClass 机制,它的原理简单来说就是:为代理类和被代理类各生成一个 Class,这个 Class 会为代理类或被代理类的方法分配一个 index(int 类)。这个 index 当做一个入参,FastClass就可以直接定位要调用的方法直接进行调用,这样省去了反射调用,所以调用效率比 JDK动态代理通过反射调用高。

13、为什么JDK Proxy 要求目标类实现接口,而CGLIB对目标类无任何要求?

JDK Proxy

在JDK Proxy中生成的代理类需要继承Proxy。获取(继承)含有InvocationHandler的构造方法,通过Proxy的InvocationHandler可以调用到invoke(), 这样才可以增强方法。在需要继承proxy类获得有关方法和InvocationHandler构造方法传参的同时,java不能同时继承两个类,我们需要和想要代理的类建立联系,只能实现一个接口

CGLIB

CGLIb的实现原理是 生成一个代理类,且代理类继承了被代理类(原类)。所以只要被代理类(原类)能被继承,也就是没有被final修饰。就可以生成代理类。

14、策略模式的本质是什么? 多个策略可以组合使用嘛?如果可以该如何设计?

策略模式的来源:

在开发中实现一个功能有很多路径,每个路径对应着有一种算法。这时候可以使用一种设计模式来实现灵活的选择解决路径,也可以方便的添加新的路径。这种模式称之为策略模式。

策略模式的的本质(目的):

策略模式主要是将算法的定义与算法的调用(使用)分开。 将算法专门定义在专门的策略类中,每一个策略类中封装了一种算法实现。 使用的时候针对 抽象策略类编程, 符合“依赖倒转原则”。在出现新的算法时,只需要增加一个新的实现了抽象策略类的具体策略类即可。 策略模式是一种 行为型模式。

多个策略可以组合使用。如果是让我来设计,1、我首先考虑用到装饰者模式,因为所有策略类都可以去继承与抽象的策略类, 假如 策略A和策略B。 策略A想要使用到策略B的算法, 那么只需要拿到策略B的引用,那么就可以取组合策略B中的算法。 2、代理模式也可以搞定。3、适配器模式可以。 4、委派模式,可以通过委派类来对具体的策略类进行组合使用。

15、代理模式和装饰器模式的区别和使用场景?

首先代理模式和装饰器模式都属于结构型模式。

区别: 代理模式主要分为: 静态代理和动态代理两种, 其中静态代理和装饰者模式实现的机制是一样的。 但是它们的目的(职责)是不一样的。装饰模式是 以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案, 它主要目的是 为所装饰的对象增强功能,装饰模式重在装饰,添加新的行为,但是不论添加什么都是方法所知道的,经过安检才装饰上的; 而代理模式是为原对象生成了一个代理类。并且有代理对象控制了原对象的引用。 也就是说原对象的一切操作,交给了代理类。代理类全权负责了, 代理类控制了原对象,并不提供对象本身的增强功能。 代理模式重在控制。可以在方法调用前,调用后增加行为,甚至彻底改变方法的行为

使用场景: 装饰者模式在源码中的使用: 在 JDK 中体现最明显的类就是 IO 相关的类,如BufferedReader、InputStream、OutputStream。一下情况可以使用装饰者模式: (1) 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。(2)当不能采用继承的方式对系统进行扩展或者采用继承不利于系统扩展和维护时可以使用装饰模式。不能采用继承的情况主要有两类:第一类是系统中存在大量独立的扩展,为支持每一种扩展或者扩展之间的组合将产生大量的子类,使得子类数目呈爆炸性增长;第二类是因为类已定义为不能被继承(如Java语言中的final类) 代理模式: 1、当客户端对象需要访问远程主机中的对象时可以使用 远程代理。2、当需要控制对一个对象的访问,为不同用户提供不同级别的访问权限时可以使用保护代理。3、 当需要为一个对象的访问(引用)提供一些额外的操作时可以使用智能引用代理。

平时怎么使用?

如果你写了一个方法,后续考虑要给这个方法添加一些功能,可以选择装饰模式。

如果你要写一堆方法,后续考虑统一给这些方法添加功能(比如日志记录,资源回收),可以选择代理模式。

16、聊聊观察者模式的设计思想。

观察者模式用于建立一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其他对象,其他对象将相应作出反应。在观察者模式中,发生改变的对象称为观察目标,而被通知的对象称为观察者,一个观察目标可以对应多个观察者,而且这些观察者之间可以没有任何相互联系,可以根据需要增加和删除观察者,使得系统更易于扩展。

观察者模式也可以被称为发布-订阅模式。 一个对象状态发生改变,其相关依赖的对象都可以得到通知,并且自动更新。

17、工作中了除了打架熟悉的MQ,还有哪些场景可以使用观察者模式?

java中的Observable类(java.util)和Observer 接口 实现了观察者模式。

Observer接口

在java.util.Observer接口中只声明一个方法,它充当抽象观察者,其方法声明代码如下所示:
​
void  update(Observable o, Object arg);

当观察目标的状态发生变化时,该方法将会被调用,在Observer的子类中将实现update()方法,即具体观察者可以根据需要具有不同的更新行为。当调用观察目标类Observable的notifyObservers()方法时,将执行观察者类中的update()方法。

Observable类

java.util.Observable类充当观察目标类,在Observable中定义了一个向量Vector来存储观察者对象,

方法名 方法描述
Observable() 构造方法,实例化Vector向量。
addObserver(Observer o) 用于注册新的观察者对象到向量中。
deleteObserver (Observer o) 用于删除向量中的某一个观察者对象
notifyObservers()和notifyObservers(Object arg) 通知方法,用于在方法内部循环调用向量中每一个观察者的update()方法。
deleteObservers() 用于清空向量,即删除向量中所有观察者对象。
setChanged() 该方法被调用后会设置一个boolean类型的内部标记变量changed的值为true,表示观察目标对象的状态发生了变化。
clearChanged() 用于将changed变量的值设为false,表示对象状态不再发生改变或者已经通知了所有的观察者对象,调用了它们的update()方法。
hasChanged() 用于测试对象状态是否改变。
countObservers() 用于返回向量中观察者的数量。

MVC(Model-View-Controller)架构中也应用了观察者模式,MVC是一种架构模式,它包含三个角色:模型(Model),视图(View)和控制器(Controller)。其中模型可对应于观察者模式中的观察目标,而视图对应于观察者,控制器可充当两者之间的中介者。当模型层的数据发生改变时,视图层将自动改变其显示内容

18、什么场景下才应该使用委派模式?

先说一下委派模式的概念。 委派模式是用来负责任务的调度和分配任务的。 还有就是委派模式不属于23种设计模式。

委派模式有点像代理模式,又有点像策略模式。

举个例子:公司老板给项目经理下达任务,将任务全权交给项目经理,由项目经理根据一定的策略将任务分配给小组成员。 这其中老板给项目经理下达任务,相当于把工作委派给了项目经理。由项目经理全权负责, 我们也可以说项目经理其实就是老板的代理。(但是代理模式注重的是过程,二委派模式注重的是结果。)项目经理在给小组成员分配任务的时候,根据不同的人擅长的技术不一样来分配任务。 这时候又特别像策略模式。

委派模式的核心就是分发、调度、派遣。也可以这么说 委派模式就是静态代理和策略模式一种特殊的组合

设计模式见解

springmvc源码中使用了委派模式。DispatcherServlet

19、为什么双亲委派一般使用继承来实现?

我理解是使用继承实现是根据加载的顺序有关系。 因为大家都知道双亲委派机制: 如果一个类加载器收到类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器完成。每个类加载器都是如此,只有当父加载器在自己的搜索范围内找不到指定的类时(即ClassNotFoundException),子加载器才会尝试自己去加载。 因为它每次加载都是先找父加载器的。 如果不使用继承的话,比如使用接口实现,那么可能会有很多接口。我们很难区分是哪个父接口是他的父加载器。 使用继承,利用单继承特性,我们就能直接找到父加载器,然后进行接下来的操作。

类加载器

  • 启动类加载器(Bootstrap ClassLoader):由C++语言实现(针对HotSpot),负责将存放在<JAVA_HOME>\lib目录或-Xbootclasspath参数指定的路径中的类库加载到内存中。

  • 其他类加载器:由Java语言实现,继承自抽象类ClassLoader。如:

    • 扩展类加载器(Extension ClassLoader):负责加载<JAVA_HOME>\lib\ext目录或java.ext.dirs系统变量指定的路径中的所有类库。

    • 应用程序类加载器(Application ClassLoader)。负责加载用户类路径(classpath)上的指定类库,我们可以直接使用这个类加载器。一般情况,如果我们没有自定义类加载器默认就是用这个加载器。

20、软件设计阶段可能应用适配器模式吗? 如果用,在什么场景下才应用?

适配器模式(Adapter模式)便是结构型中的其中一个模式,它的作用是:将一个类的接口转换成客户希望的另外一个接口。Adapter模式使原本由于接口不兼容而不能在一起工作的类可以一起工作。 适配器模式应用场景   (1)想要使用一个已经存在的类,但是它却不符合现有的接口规范,导致无法直接去访问,这时创建一个适配器就能间接去访问这个类中的方法。   (2)我们有一个类,想将其设计为可重用的类(可被多处访问),我们可以创建适配器来将这个类来适配其他没有提供合适接口的类。   以上两个场景其实就是从两个角度来描述一类问题,那就是要访问的方法不在合适的接口里,一个从接口出发(被访问),一个从访问出发(主动访问)。 ​ 一般在软件设计阶段不会考虑适配器模式,而是在随着软件维护,由于不同产品不同厂家造成功能相同而接口不同的情况下的解决方案。

而在设计阶段中,如果想要使用接口中的某个或某些方法,但是接口中有太多方法,我们要使用时必须实现接口并实现其中的所有方法,可以使用抽象类来实现接口,并不对方法进行实现(仅置空),然后我们再继承这个抽象类来通过重写想用的方法的方式来实现。这个抽象类就是适配器。这种场景下会使用到适配器模式。

21、模板方法模式如何与其他设计模式结合?

先说一下模板模式吧。 模板模式是一种基于继承的代码复用技术。是一种类行为型模式。

一个模板方法是定义在抽象类中的、把基本操作方法组合在一起形成一个总算法或一个总行为的方法。这个模板方法定义在抽象类中,并由子类不加以修改地完全继承下来。模板方法是一个具体方法,它给出了一个顶层逻辑框架,而逻辑的组成步骤在抽象类中可以是具体方法,也可以是抽象方法。由于模板方法是具体方法,因此模板方法模式中的抽象层只能是抽象类,而不是接口

模板方法模式中,在父类中提供了一个定义算法框架的模板方法,还提供了一系列抽象方法、具体方法和钩子方法,其中钩子方法的引入使得子类可以控制父类的行为

1、模板方法模式可以和策略模式结合起来使用,具体的模板方法类,实现了抽象类之后,可以引入策略模式,根据不同的业务需求,选择最好的算法来解决问题

2、模板方法模式可以和装饰者模式结合, 因为两种模式都是基于继承的,所以在模板方法中可以使用装饰者模式来增加某个具体的模板方法。

22、责任链模式能解决什么问题?如何解决?

责任链模式(Chain of Responsibility)

定义: 避免发送者和接受者耦合在一起, 让多个对象都有可能接收请求,让这些对象连接成一条链, 并且让这条链传递请求, 知道有对象处理请求为止。 是一种行为型模式。

职责链模式并不创建职责链,职责链的创建工作必须由系统的其他部分来完成,一般是在使用该职责链的客户端中创建职责链

责任链模式中,一个处理者只有两种选择: 1、承担全部责任, 2、将责任推给下家。

使用场景: 在Web应用开发中创建一个过滤器(Filter)链来对请求数据进行过滤,在工作流系统中实现公文的分级审批等等,使用职责链模式可以较好地解决此类问题。 如果我们遇到这种需求: 有多个对象可以处理同一个请求,具体哪个对象处理该请求待运行时刻再确定,客户端只需将请求提交到链上,而无须关心请求的处理对象是谁以及它是如何处理的。 我们就可以使用责任链模式。

责任链解决问题的优势:

1、请求处理对象仅需维持一个指向其后继者的引用,而不需要维持它对所有的候选处理者的引用,可简化对象的相互连接。2、在给对象分派职责时,职责链可以给我们更多的灵活性,可以通过在运行时对该链进行动态的增加或修改来增加或改变处理一个请求的职责。3、 在系统中增加一个新的具体请求处理者时无须修改原有系统的代码,只需要在客户端重新建链即可,从这一点来看是符合“开闭原则”的。