其实策略模式就是对算法的包装,是把算法的责任和算法本身分割开来,委派给不同的对象管理,最终实现解决多重if判断问题。如果在一个系统中有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为(算法),也就是上面所说解决了多重if判断问题。
使用场景:

第一种:通过接口来实现,不同的类通过实现这个接口实现不同的功能,最后存到map中(手动注册),在使用的时候按需要来获取不同的接口实现类对象来执行方法。
第二种:实现InitializingBean接口(自动注册),策略类实现InitializingBean接口,并自动注册。该实现类必须要有@Component、@Service注解,否则afterPropertiesSet方法将不起作用! 因为只有bean被初始化时,才会执行afterPropertiesSet方法!!!
第三种:基于SpringBoot实现策略模式
上下文这个类,你可以把公用的代码写在该类中。上层的调用需要与接口之间有一定的交互。交互的可能是一些属性,或是一些方法。这样的交互往往会让接口变的难以调用;于是上下文的引入就是势在必行。将相关的属性或一些公共的方法封装到上下文中,让上下文去和接口进行复杂的交互。而上层的调用只需要跟上下文打交道就可以。
优点:
缺点:
定义一个操作中的算法骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的。重复代码全部在父类里面,不同业务的,使用抽象方法,抽取给子类进行实现。抽取过程—抽象方法。就是将一些相同操作的代码,封装成一个算法的骨架。核心的部分留在子类中操作,在父类中只把那些骨架做好。
应用场景:数据库访问的封装、Junit单元测试、servlet中关于doGet()/doPost()方法的调用
策略模式核心在使用者的策略。 如果按照自己的策略去替换。模板方法模式核心在子类的怎么实现。
优点:
缺点:
按照设计习惯,抽象类负责声明最抽象、最一般的事物属性和方法,实现类负责完成具体的事务属性和方法,但是模板方式正好相反,子类执行的结果影响了父类的结果,会增加代码阅读的难度
当一个请求可能需要被多个对象处理时,我们可以将这些处理对象链成一条链,并在这条链上传递该请求,直到该请求被处理完毕,这种设计模式就叫做责任链设计模式。

多个对象可以处理同一请求,但具体由哪个对象处理则在运行时动态决定;
在不明确指定接收者的情况下,向多个对象中的一个提交一个请求;
可动态指定一组对象处理请求;
责任链设计模式将每个处理请求的对象都当成链上的一个节点,这些对象(节点)中都有一个处理请求的方法,每个节点又可以设置它的下一节点,从而形成一条处理链,在本节点处理请求之后可以选择是否将请求继续传递给下一个节点进行处理。
优点:
降低耦合度。它将请求的发送者和接收者解耦
简化了对象,使得对象不需要知道链的结构
增强给对象指派职责的灵活性,允许动态地新增或者删除责任链
增加新的请求处理类方便
缺点:
不能保证请求一定被接收;
系统性能将受到一定影响,调试时不方便,可能会造成循环调用
装饰模式,是面向对象编程领域中,一种动态地往一个类中添加新的行为的设计模式。就功能而言,装饰模式相比生成子类更为灵活,这样可以给某个对象而不是整个类添加一些功能。
应用场景:

就是你拿一个类A来封装另外一个类B,但没有继承关系,
这两个类可实现相通的接口,在A中的每个方法调用B的对应方法来实现逻辑,
并在调用前后加入自己的处理来改变方法的行为。
优点:
缺点:
除了当前类能够提供的功能外,我们还需要补充一些其他功能。最容易想到的情况就是权限过滤,我有一个类做某项业务,但是由于安全原因只有某些用户才可以调用这个类,此时我们就可以做一个该类的代理类,要求所有请求必须通过该代理类,由该代理类做权限判断,如果安全则调用实际类的业务开始处理。可能有人说为什么我要多加个代理类?我只需要在原来类的方法里面加上权限过滤不就完了吗?在程序设计中有一个类的单一性原则问题,这个原则很简单,就是每个类的功能尽可能单一。为什么要单一,因为只有功能单一这个类被改动的可能性才会最小,就拿刚才的例子来说,如果你将权限判断放在当前类里面,当前这个类就既要负责自己本身业务逻辑、又要负责权限判断,那么就有两个导致该类变化的原因,现在如果权限规则一旦变化,这个类就必需得改,显然这不是一个好的设计。
应用场景:
静态代理:实例和代理类都实现了同一个接口,不管传递什么实例进代理类中都能调用方法,不需要在每个新生成的实例中重复写某一个方法。
jdk动态代理:Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类:
(1) Interface InvocationHandler:该接口中仅定义了一个方法
public objectinvoke(Object obj, Methond method, Object[] args)在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,args为该方法的参数数组。
(2) Proxy:该类即为动态代理类
static ObjectnewProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类在接口中声明过的方法)
CGLIB动态代理:cglib也是动态代理,不同于proxy,它不需要基于接口进行代理,利用asm字节码技术,生成子类实现对目标方法实现增强
静态代理:由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。
动态代理:动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以不存在代理类的字节码文件。代理类和委托类的关系是在程序运行时确定。
区别:动态代理不需要写代理类对象,通过程序自动生成,而静态代理需要我们自己写代理类对象。
第一种:JDK动态代理
实现步骤:
1.创建被代理的接口和类;
2.实现InvocationHandler接口,对目标接口中声明的所有方法进行统一处理;
3.调用Proxy的静态方法,创建代理类并生成相应的代理对象;
第二种:CGLIB动态代理
利用asm字节码技术,生成子类实现对目标方法实现增强
创建代理类$Proxy0源代码文件实现被代理的接口。
使用JavaCompiler技术编译该 Proxy 0 文 件 获 取 到 Proxy0文件获取到 Proxy0文件获取到Proxy0.class
使用ClassLoader将该$Proxy0.class加入到当前JVM内存中。
ClassLoader 顾名思义就是类加载器。ClassLoader 作用:负责将 Class 加载到 JVM 中,审查每个类由谁加载(父优先的等级加载机制),将 Class 字节码重新解析成 JVM 统一要求的对象格式。
优点:
代理模式能够协调调用者和被调用者,在一定程度上降低了系统的耦合度;
代理对象可以在客户端和目标对象之间起到中介的作用,这样起到了保护目标对象的作用;
缺点:
由于在客户端和真实对象之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢;
实现代理模式需要额外的工作,有些代理模式的实现非常复杂;
静态代理在委托类变多的情况时会显的非常臃肿,不方便阅读与使用;
观察者模式(Observer),又叫发布-订阅模式(Publish/Subscribe),定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新。
关联行为场景、事件多级触发场景、跨系统的消息变换场景,如消息队列的处理机制。
业务使用场景:
手机丢了,委托别人给其他人发消息通知
通知老师/老板来了
拍卖,拍卖师观察最高标价,然后通知给其它竞价者竞价
在一个目录下建立一个文件,会同时通知目录管理器增加目录,并通知磁盘减少空间,文件是被观察者,目录管理器和磁盘管理器是观察者
猫叫了一声,吓着了老鼠,也惊到了主人,猫是被观察者,老鼠和人是观察者
Observer接口
Observer为java.util包下的一个接口,源码如下:
public interface Observer {
void update(Observable o, Object arg);
}
该接口约定了观察者的行为。所有观察者需要在被观察对象发生变化时做出相应的反应,所做的具体反应就是实现Observer接口的update方法,实现update方法时你可以用到两个参数,一个参数的类型是Observable,另一个参数的类型是Object。当然如果完全由自己去实现一个观察者模式的方案,自己去设计Observer接口时,可能不会设计这两个参数。那为什么jdk设计该接口时规定接口中有这两个参数呢?那就是通用性。想想整个观察者模式有哪些类之间需要交互?使用该模式时牵扯三个类,一个是观察者,一个是被观察对象,一个是调用者(调用者可以是被观察对象本身调用,更多情况是一个具体的业务类),当前接口代表观察者,要与被观察对象交互,因此update方法需要持有被观察对象(Observable)的引用,第一参数产生了;如何与调用者通信,则是添加了类型为Object的参数(该参数是调用者调用Observable实例的notifyObservers(Object obj)方法时传入的,当然也可以不传);第一个参数可以说是为观察者提供了一种拉取数据的方式,update中的业务可以根据所需去拉去自己想要的被观察对象的信息(一般被观察对象中提供getter),第二个参数则是由调用者调用notifyObservers(Object obj)将一些信息推过来。通过这两个参数,观察者,被观察对象,调用者(调用通知刷新方法的可能是被观察对象本身,此时只存在观察者与被观察者两者)三者就联系起来了。
Observable类
Observable同样是java.util包下的接口(理所当然的事),该类的成员变量和方法如下:
public class Observable {
private boolean changed = false;
private Vector<Observer> obs;
public Observable(){};
protected synchronized void setChanged(){};
protected synchronized void clearChanged(){};
public synchronized void addObserver(Observer o){};
public synchronized void deleteObserver(Observer o) {};
public synchronized void deleteObservers(){};
public synchronized boolean hasChanged(){};
public synchronized int countObservers(){};
public void notifyObservers(){};
public void notifyObservers(Object arg){};
}
说说成员变量:
1)该类中含有一个boolean型的变量changed,代表是否发生改变了,Observable类只提供这个boolean值来表明是否发生变化,而不定义什么叫变化,因为每个业务中对变化的具体定义不一样,因此子类自己来判断是否变化;该变量既提供了一种抽象(变与不变),同时提供了一种观察者更新状态的可延迟加载,通过后面的notifyObservers方法分析可知观察者是否会调用update方法,依赖于changed变量,因此即使被观察者在逻辑上发生改变了,只要不调用setChanged,update是不会被调用的。如果我们在某些业务场景不需要频繁触发update,则可以适时调用setChanged方法来延迟刷新。
2)该类含有一个集合类Vector,该类泛型为Observer,主要用来存放所有观察自己的对象的引用,以便在更新时可以挨个遍历集合中的观察者,逐个调用update方法
说明:
1.8的jdk源码为Vector,有版本的源码是ArrayList的集合实现;
Vector这个类和ArrayList的继承体系是一致,主要有两点不同,一是Vector是线程安全的,ArrayList不是线程安全的,Vector的操作依靠在方法上加了同步关键字来保证线程安全,与此同时ArrayList的性能是要好于Vector的;二是Vector和ArrayList扩容阀值不太一样,ArrayList较Vector更节省空间;
说说方法:
1)操作changed变量的方法为setChanged(),clearChanged(),hasChanged();见名知意,第一个设置变化状态,第二清除变化状态,这两个的访问权限都是protected,表明这两个方法由子类去调用,由子类来告诉什么时候被观察者发生变化了,什么时候变化消失,而hasChanged()方法的访问权限是公有的,调用者可以使用该方法。三个方法都有同步关键字保证变量的读写操作线程安全。
2)操作Vector类型变量obs的方法为addObserver(Observer o), deleteObserver(Observer o), deleteObservers(),countObservers(),这四个方法分别实现了动态添加观察者,删除观察者,删除所有观察者,获取观察者数量。四个方法的访问权限都是公有的,这是提供给调用者的方法,让调用者来实时动态的控制哪些观察者来观察该被观察对象。
3)操作Vector型变量obs的四个方法都加有同步关键字,但是我们刚才分析成员属性Vector obs这个变量时,说Vector类型为线程安全的,而上述四个方法为什么还要加同步关键字呢,这是怎么回事?据我推测应该是程序员重构遗留问题吧,因为前面我说道,有历史版本的源码是使用的ArrayList来持有Observer的引用,而ArrayList不是线程安全的,所以上述四个操作结合的方法需要加上同步关键字来保证线程安全,而后来换成线程安全的Vector了,但这四个操作集合的方法依旧保留了同步关键字。
4)两个对外的方法notifyObservers(),notifyObservers(Object arg),该方法由调用者来操作,用来通知所有的观察者需要做更新操作了。

四个角色
在上述类图中,ConcreteSubject中有一个存储Observer的列表,这意味着ConcreteSubject并不需要知道引用了哪些ConcreteObserver,只要实现(继承)了Observer的对象都可以存到该列表中。在需要的时候调用Observer的update方法。
Subject:

Observer:

ConcreteSubject:
/**
* 具体主题
*/
public class ConcreteSubject implements Subject {
private List<Observer> observerList = new ArrayList<>();
private String state;
@Override
public void attach(Observer observer) {
this.observerList.add(observer);
System.out.println("向ConcreteSubject注册了一个观察者");
}
@Override
public void detach(Observer observer) {
this.observerList.remove(observer);
System.out.println("从ConcreteSubject移除了一个观察者");
}
//遍历观察者发出通知
@Override
public void notifyObservers() {
this.observerList.forEach(observer -> observer.update(this.state));
}
//发通知给观察者
public void changeState(String state) {
this.state = state;
this.notifyObservers();
}
}
ConcreteObserver:

测试类:MyObserverTest:

是一种通过为多个复杂的子系统提供一个一致的接口,而使这些子系统更加容易被访问的模式。该模式对外有一个统一接口,外部应用程序不用关心内部子系统的具体的细节,这样会大大降低应用程序的复杂度,提高了程序的可维护性。
2、使用门面模式重构支付回调业务逻辑代码(代码任务)
答:
3、什么是状态模式,状态模式与策略模式的区别
答:
适配器模式
1、什么是适配器模式?适配器模式原理
答:
2、适配器的应用场景
答:
3、请使用适配器编写案例一个参数支持多种类型(代码实战)
答:
4、myabtis适配器源码分析
答:
单例模式
深入理解单例
1、什么是单例模式?
答:
2、单例模式有哪些创建方式?
答:
3、饿汉式与懒汉式区别?
答:
4、双重检验锁两个if判断作用
答:
5、静态内部类方式与双重检验锁的区别?
答:
6、如何破坏一个单例?
答:
7、java序列的作用有哪些?
答:
8、请完成七种单例模式代码编写
答:
深入理解枚举单例底层实现原理
1、枚举单例底层是如何实现的?(源码解析流程图)
答:
2、为什么反射无法初始化枚举对象?
答: