单例设计模式:
1. 利用类的静态属性生成对象: ( 缺点: 不能进行Lazy Load )
public class SingletonObject1 {
/**
* can't lazy load
*/
private final static SingletonObject1 instance=new SingletonObject1();
static {
System.out.println("singleton 类的初始化");
}
public static SingletonObject1 getInstance(){
System.out.println("加载返回实例"
);
return instance;
}
}
2.double check : 可以进行lazy load ; 形成过程比较曲折;
public class doubleCheck{
private SingletonObject2 instance;
private SingletonObject2() {
}
/**
* double check的算法
*
* First check : 简单 的创建一下是否创建了单例
* Second check : 是要锁住创建实例的过程
*
* 如果即实现了lazy load
* 又解决了Synchronized的导致效率降低的问题
* 这样只有开始的时候就进入了同步块;
* 其他的时候直接不用进入同步块;
*
*
*
* 但是会出现一个问题: 就是返回instance的过程中,这个instance并没有初始化完成,
* 但在这个时候,别的线程可能已经在使用这个instance;
* @return
*/
private SingletonObject2 getInstance(){
if(instance==null){
synchronized (SingletonObject2.class){
if(instance==null){
instance= new SingletonObject2();
}
}
}
return instance;
}
}
很明显上面会出现并发问题: 生成并发问题的原因就是Java指令的重排序,那麽如何打破这个问题的出现呢?----volatile 关键字来实现
大家如果不懂的话可以进行参考volatile关键字的详解;
所以说真正实现doublecheck的方式为:
public class SingletonObject3 {
/**
* volatile : 作用: volatile在读的过程中,在读的过程看到的写必须完全完成
* 这样就能保证,instance的实例已经全部完成;
*/
private volatile SingletonObject3 instance;
private SingletonObject3() {
}
private SingletonObject3 getInstance(){
if(instance==null){
synchronized (SingletonObject3.class){
if(instance==null){
instance= new SingletonObject3();
}
}
}
return instance;
}
}
3.利用静态内部类来实现lazy load的效果;
public class inner_static_class {
private SingletonObject6 instance;
private SingletonObject6() {
}
/**
*内部静态类的属性成员 不会在加载类的时候被初始化,只有在调用的时候才会被初始化。也就是内部类是lazy load;
*/
private static class InstanceHolder{
private static final SingletonObject6 instance =new SingletonObject6();
static {
System.out.println(" static class is load ");
}
}
public static SingletonObject6 getInstance(){
return InstanceHolder.instance;
}
}
官方单例模式的形成: 利用枚举类中的一个枚举只生成一次,也就是只有一次调用构造函数的特点,而且还是lazy load的;
public class SingletonObject8 {
private SingletonObject8(){
}
/**
* 枚举类型的类和内部静态类相同具有lazy load 的效果,而且只加载一次;
*/
private enum Singleton{
INSTANCE;
private final SingletonObject8 instance;
Singleton(){
System.out.println("枚举类型已经被初始化" );
instance=new SingletonObject8();
}
public SingletonObject8 getInstance(){
return instance;
}
}
public static SingletonObject8 getInstance(){
return Singleton.INSTANCE.getInstance();
}
}
php中简单实现单例模式:
//todo 单例模式的实现
class Dog0 {
private static $instance ;
private function __construct()
{
}
public static function getInstance(){
if (! self::$instance){
$instance = new Dog0();
}
return self::$instance;
}
}
单例模式的应用场景:
以下都是单例模式的经典使用场景:
1.资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如上述中的日志文件,应用配置。
2.控制资源的情况下,方便资源之间的互相通信。如线程池等。
应用场景举例:
1.外部资源:每台计算机有若干个打印机,但只能有一个PrinterSpooler,以避免两个打印作业同时输出到打印机。
内部资源:大多数软件都有一个(或多个)属性文件存放系统配置,这样的系统应该有一个对象管理这些属性文件
2. Windows的Task Manager(任务管理器)就是很典型的单例模式(这个很熟悉吧),想想看,是不是呢,你能打开两个windows task manager吗? 不信你自己试试看哦~
3. windows的Recycle Bin(回收站)也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。
4. 网站的计数器,一般也是采用单例模式实现,否则难以同步。
5. 应用程序的日志应用,一般都何用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否 则内容不好追加。
6. Web应用的配置对象的读取,一般也应用单例模式,这个是由于配置文件是共享的资源。
7. 数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源。数据库软件系统中使用数据库连接池,主要是节省 打开或者关闭数据库连接所引起的效率损耗,这种效率上的损耗还是非常昂贵的,因为何用单例模式来维护,就可以大大降低这种损 耗。
8. 多线程的线程池的设计一般也是采用单例模式,这是由于线程池要方便对池中的线程进行控制。
9. 操作系统的文件系统,也是大的单例模式实现的具体例子,一个操作系统只能有一个文件系统。
10. HttpApplication 也是单位例的典型应用。熟悉ASP.Net(IIS)的整个请求生命周期的人应该知道HttpApplication也是单例模式,所有的 HttpModule都共享一个HttpApplication实例.
适用场景: 1.需要生成唯一序列的环境
2.需要频繁实例化然后销毁的对象。
3.创建对象时耗时过多或者耗资源过多,但又经常用到的对象。
4.方便资源相互通信的环境
优点:1.实现了对唯一实例访问的可控
2.对于一些需要频繁创建和销毁的对象来说可以提高系统的性能。
装饰者模式: 在原先的类的基础上对类进行功能的拓展
代码的实现方式:
public interface Sourceable {
public void method();
}
//基础类:
public class Source implements Sourceable {
@Override
public void method() {
System.out.println("the original method!");
}
}
//在基础类的基础上进行功能拓展
public class Decorator implements Sourceable {
private Sourceable source;
public Decorator(Sourceable source){
super();
this.source = source;
}
@Override
public void method() {
System.out.println("before decorator!");
source.method();
System.out.println("after decorator!");
}
}
//测试;
public class Main {
public static void main(String[] args) {
Sourceable source = new Source();
Sourceable obj = new Decorator(source);
obj.method();
}
}
由于java I/O库需要很多性能的各种组合,如果这些性能都是用继承来实现,那么每一种组合都需要一个类,这样就会造成大量行重复的类出现。如果采用装饰模式,那么类的数目就会大大减少,性能的重复也可以减至最少。因此装饰模式是java I/O库基本模式。装饰模式的引进,造成灵活性和复杂性的提高。因此在使用 java I/O 库时,必须理解java I/O库是由一些基本的原始流处理器和围绕它们的装饰流处理器所组成的。
应用场景:
InputStream类是以抽象组件的形式存在,而FileInputStream就是具体组件,它实现了抽象接口的所有方法,并且持有InputStream对象的引用。FileInputStream就是一个装饰类。同理,FilterInputStream就是inputStream基础组件的装饰者;
BufferedInputStream是这个装饰类的具体实现者,它给FilterInputStream加入了新的功能,使得FilterInputStream读取的数据保存在内存中,从而提高读取性能
适配器模式:
我们想要的规定的接口中调用某个类的功能;也就是说,我们将对象的一些功能适配到比较标准的容易理解的接口规范方法中;
应用场景: 我们想复用一个类的一项技能,同时要想扩展新的技能,然后把这些技能放在新的抽取的接口中;
--------------就用这种模式来实现这种功能;
基础工具类:
/**
* 原始类
*/
public class Source {
public void method1() {
System.out.println("this is original method!");
}
}
现在我们将这个类的方法适配到一个接口规范中:
对象的适配器模式:
/**
* 再调用上实现简单的适配效果,但不是在根本上的调用;
*/
public class Wrapper implements Targetable {
private Source source;
public Wrapper(Source source){
super();
this.source = source;
}
@Override
public void method2() {
System.out.println("this is the targetable method!");
}
@Override
public void method1() {
source.method1();
}
}
应用场景:
整合框架(获取环境信息):
我们在整合一些框架的时候,框架的内部都有一些关于得到环境信息的接口;需要从外部引入,这样就需要适配器模式来转换,借助于原框架类的功能,按照整合框架的格式输送给他;
总结:整合框架,想要向新的框架输送信息;必须按照它规定的接口的那种格式,这样才能将其适配,这就是所谓的适配器模式;
Jdk中的举例: Java的I/O类库中有许多这样的需求,如将字符串转成字节数据保存到文件中,将字节数据变成数据流等。具体来说,InputStreamReader和OutputStreamWriter就是适配器的体现。InputStreamReader实现了Reader接口,并且持有InputStream的引用,其作用是将InputStream适配到Reader。源角色就是InputStream代表的实例对象,目标角色就是Reader类。OutputStreamWriter也是类似的方式。
将inputStream的功能,整合到reader的格式进行读取;
接口的适配器
: 只实现接口的一个方法;中间加一个空实现的抽象类,重写方法便可;
类的适配器模式:
利用继承的方式去调用一些类的功能来适配接口规范;
public class Adapter extends Source implements Targetable {
@Override
public void method2() {
System.out.println("this is the targetable method!");
}
}
类的适配器和对象的适配器的区别:
对象适配器与类适配器不同之处在于,类适配器通过继承来完成适配,对象适配器则是通过关联来完成
适配器模式的典型应用:
spring AOP中的适配器模式:
在Spring的Aop中,使用的 Advice(通知) 来增强被代理类的功能。
Advice的类型有:MethodBeforeAdvice、AfterReturningAdvice、ThrowsAdvice
在每个类型 Advice 都有对应的拦截器,MethodBeforeAdviceInterceptor、AfterReturningAdviceInterceptor、ThrowsAdviceInterceptor
Spring需要将每个 Advice 都封装成对应的拦截器类型,返回给容器,所以需要使用适配器模式对 Advice 进行转换。
这里就是 基础类advisor ----> 适配器模式 ----> ( 规定的接口规范 )顺便 转换成对应的拦截器类型
实现方式:
三个基础类各自实现的接口;
public interface MethodBeforeAdvice extends BeforeAdvice {
void before(Method var1, Object[] var2, @Nullable Object var3) throws Throwable;
}
public interface AfterReturningAdvice extends AfterAdvice {
void afterReturning(@Nullable Object var1, Method var2, Object[] var3, @Nullable Object var4) throws Throwable;
}
public interface ThrowsAdvice extends AfterAdvice {
}
要把advisor 适配到 的接口规范 ,这里 使用 函数入口的传参的方式 调用 基础类
三个适配器类 Adapter 分别如下
class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
@Override
public boolean supportsAdvice(Advice advice) {
return (advice instanceof MethodBeforeAdvice);
}
@Override
public MethodInterceptor getInterceptor(Advisor advisor) {
MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
return new MethodBeforeAdviceInterceptor(advice);
}
}
@SuppressWarnings("serial")
class AfterReturningAdviceAdapter implements AdvisorAdapter, Serializable {
@Override
public boolean supportsAdvice(Advice advice) {
return (advice instanceof AfterReturningAdvice);
}
@Override
public MethodInterceptor getInterceptor(Advisor advisor) {
AfterReturningAdvice advice = (AfterReturningAdvice) advisor.getAdvice();
return new AfterReturningAdviceInterceptor(advice);
}
}
class ThrowsAdviceAdapter implements AdvisorAdapter, Serializable {
@Override
public boolean supportsAdvice(Advice advice) {
return (advice instanceof ThrowsAdvice);
}
@Override
public MethodInterceptor getInterceptor(Advisor advisor) {
return new ThrowsAdviceInterceptor(advisor.getAdvice());
}
}
调用适配器中的方法,得到我们想要的对应的方法拦截器;
public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {
private final List<AdvisorAdapter> adapters = new ArrayList(3);
public DefaultAdvisorAdapterRegistry() {
// 这里注册了适配器
this.registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
this.registerAdvisorAdapter(new AfterReturningAdviceAdapter());
this.registerAdvisorAdapter(new ThrowsAdviceAdapter());
}
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList(3);
Advice advice = advisor.getAdvice();
if (advice instanceof MethodInterceptor) {
interceptors.add((MethodInterceptor)advice);
}
Iterator var4 = this.adapters.iterator();
while(var4.hasNext()) {
AdvisorAdapter adapter = (AdvisorAdapter)var4.next();
if (adapter.supportsAdvice(advice)) { // 这里调用适配器方法
interceptors.add(adapter.getInterceptor(advisor)); // 这里调用适配器方法
}
}
if (interceptors.isEmpty()) {
throw new UnknownAdviceTypeException(advisor.getAdvice());
} else {
return (MethodInterceptor[])interceptors.toArray(new MethodInterceptor[0]);
}
}
// ...省略...
}
这里看 while 循环里,逐个取出注册的适配器,调用 supportsAdvice()
方法来判断 Advice
对应的类型,然后调用 getInterceptor()
创建对应类型的拦截器
SpringMVC中HandlerAdapter的使用:
记得之前写的一篇的文章springmvc基本原理讲解中提到了 在利用Handlermapping处理后得到每个相对应的Handler,通过调用HandlerAdapter来调用他 这个步骤;
为甚麽要使用适配器模式?
Spring MVC中的适配器模式主要用于执行目标 Controller 中的请求处理方法。
在Spring MVC中,DispatcherServlet 作为用户,HandlerAdapter 作为期望接口,具体的适配器实现类用于对目标类进行适配,Controller 作为需要适配的类。
为什么要在 Spring MVC 中使用适配器模式?Spring MVC 中的 Controller 种类众多,不同类型的 Controller 通过不同的方法来对请求进行处理。如果不利用适配器模式的话,DispatcherServlet 直接获取对应类型的 Controller,需要的自行来判断,像下面这段代码一样:
if(mappedHandler.getHandler() instanceof MultiActionController){
((MultiActionController)mappedHandler.getHandler()).xxx
}else if(mappedHandler.getHandler() instanceof XXX){
...
}else if(...){
...
}
样假设如果我们增加一个 HardController
,就要在代码中加入一行 if(mappedHandler.getHandler() instanceof HardController)
,这种形式就使得程序难以维护,也违反了设计模式中的开闭原则 – 对扩展开放,对修改关闭。
下面利用适配器模式,通过适配器集合来遍历寻找合适的适配器,这样就比较优雅了
Controller 有很多种类也就是Handler 有多种,这里是对其中的一种 HttpRequestHandler 处理器来编写适配器
public class HttpRequestHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
return (handler instanceof HttpRequestHandler);
}
通过调用适配器来调用请求
@Override
@Nullable
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
((HttpRequestHandler) handler).handleRequest(request, response);
return null;
}
@Override
public long getLastModified(HttpServletRequest request, Object handler) {
if (handler instanceof LastModified) {
return ((LastModified) handler).getLastModified(request);
}
return -1L;
}
}
通过遍历 处理映射器 找到 符合这个请求的 处理执行链 HandlerExecution
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
得到符合当前处理器的处理器适配器
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) {
return adapter;
}
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
springMVC的核心调用处理方式:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
通过遍历处理器映射器 准确的查出符合当前请求的处理器
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
得到符合当前处理器的处理器适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
Actually invoke the handler.
使用处理适配器实际处理了这次请求
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
。。。。。。
工厂方法设计模式:
SpringBean的产生基本上都是利用工厂方法设计模式产生的;
演示:
基础类;
public interface Sender {
public void Send();
}
两个实现类:
public class SmsSender implements Sender {
@Override
public void Send() {
System.out.println("this is sms sender!");
}
}
public class MailSender implements Sender {
@Override
public void Send() {
System.out.println("this is mailsender!");
}
}
比较简陋的工厂方法的实现
public class SendFactory {
public Sender produce(String type) {
if ("mail".equals(type)) {
return new MailSender();
} else if ("sms".equals(type)) {
return new SmsSender();
} else {
System.out.println("请输入正确的类型!");
return null;
}
}
}
或者:
public class SendFactory {
public Sender produceMail(){
return new MailSender();
}
public Sender produceSms(){
return new SmsSender();
}
}
静态方法的工厂实现
public class SendFactory {
public static Sender produceMail(){
return new MailSender();
}
public static Sender produceSms(){
return new SmsSender();
}
}
抽象工厂方法模式:
public interface Provider {
public Sender produce();
}
public class SendMailFactory implements Provider {
@Override
public Sender produce(){
return new MailSender();
}
}
public class SendSmsFactory implements Provider{
@Override
public Sender produce() {
return new SmsSender();
}
}
工厂模式的应用
优点:
1. 工厂模式具有良好的封装性,代码结构清晰,也有利于扩展。在增加产品类的情况下,只需要适当地修改具体的工厂类或扩展一个工厂类,就可以完成“拥抱变化”。
2. 工厂模式可以屏蔽产品类。这一点非常重要,产品类的实现如何变化,调用者都不用关系,只需要关心产品的接口,只要接口保持不变,系统的上层模块就不需要发生变化。
3. 工厂模式是典型的解耦框架。高层模块只需要知道产品的抽象类,其他的实现类都不用关心。
PHP中实现工厂方法模式
//todo 工厂模式的实现:----程序发生创建对象时的改动的时候 对整体的影响不会太大;
//todo 如果 写的程序中需要大量的创建这个Dog对象 $a =new Dog();
//todo 但是如果到出这样写的话,就会造成你的程序和Dog 这个对象的依赖耦合特别高;
/******************************问题**********************************/
// todo 问题一 : 如果此时你想用一只 🐯 来看门 ,所以这个地方就不好改了。
// todo 问题二: 如果你写的Dog的方法的construct 有改动参数;这时也是不好改了
/******************************问题**********************************/
//todo 那么怎么解决这个问题呢? ------ 工厂模式帮你解决;
//todo 看门这个技能;
interface Kanmen{
function kanmen ();
}
class Dog_see implements Kanmen {
public function kanmen()
{
echo 'wang wang wang !';
}
}
class Tiger implements Kanmen{
public function kanmen()
{
echo ' Hong !';
}
}
//todo 在这里先用来解决第二个问题;你new的对象的构造参数发生改变了------------封装抽取----------
class Factory {
static function getkanmen($name){
if ($name == 'Dog'){
return new Dog_see();
}else if ($name == 'tiger'){
return new Tiger();
}
}
}
$daog=Factory::getkanmen('Dog');
//todo 我们可以通过一个工厂来封装这个对象的新建,这样如果对象的新建发生改变的时候,只改工厂其他地方就相当于都改了;
//todo 总结 : 对一个事物的封装 。抽取,一次封装,处处调用;
//todo 这样的耦合度就太高了 ,我们现在不想用Dog来看门了,我们想换一个更厉害的球员 这怎么办 ;
//todo 这样无非用到了 设计模式中的 依赖倒置原则 高层依赖于底层 interface 这样我们就可以原先的类不用改动只改动入口参数
//todo new Host(kanmen 看门);这样我们可以注入dog 也可以注入tiger;
/******************************问题**********************************/
//todo 然后我们再返回头来看 Factory 可以看到这个工厂的扩展性特别烂 。说明 他的粒度特别大,抽取接口,各自实现将粒度缩小;
interface Factory0 {
public function createKanmen();
}
class Dog_Factory implements Factory0{
public function createKanmen(){
return new Dog_see();
}
}
class Tig_Factory implements Factory0{
public function createKanmen(){
return new Tiger();
}
}
//todo successful Design Pattern
//todo 1.我们这样设计的时候就可以随时改动Dog的创建方式; 只需要改动工厂就好了;
//todo 2.在一个就是进行引用的时候,我们可以采用 依赖倒置的 方式,随时替换球员;
$kanmen0 =new Dog_see();
建造者模式:
将构建新对象的组件 和 组件的构建逻辑实现了 解耦;
实现的代码:
public class Main {
public static void main(String[] args) {
//创建构建逻辑
Director director = new Director();
//形成构建的具体组件
Builder b1 = new ConcreateBuilder1();
Builder b2 = new ConcreateBuilder2();
//把组件交付给管家进行逻辑构建
director.Construct(b1);
Product p1 = b1.GetResult();
p1.show();
director.Construct(b2);
Product p2 = b2.GetResult();
p2.show();
}
}
构建一种复杂对象的构建组件 组合 接口;
public abstract class Builder {
public abstract void buildPartA();
public abstract void buildPartB();
public abstract Product GetResult();
}
构建这种复杂对象的一个实例类
public class ConcreateBuilder1 extends Builder {
private Product product = new Product();
@Override
public void buildPartA() {
product.add("部件A");
}
@Override
public void buildPartB() {
product.add("部件B");
}
@Override
public Product GetResult() {
return product;
}
}
组件之间的构建逻辑:
public class Director {
/**
* 决定了组件之间的构建逻辑
* @param builder
*/
public void Construct(Builder builder){
builder.buildPartA();
builder.buildPartB();
}
}
最后产生的商品
public class Product {
List parts = new ArrayList();
public void add(String part){
parts.add(part);
}
public void show(){
System.out.println("产品创建----");
for (Object part : parts) {
System.out.println(part);
}
}
}
应用举例:
mybatis 中的建造者模式:
我们来看 org.apache.ibatis.session
包下的 SqlSessionFactoryBuilder
类
里边很多重载的 build
方法,返回值都是 SqlSessionFactory
,除了最后两个所有的 build
最后都调用下面这个 build
方法
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
SqlSessionFactory var5;
try {
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
var5 = this.build(parser.parse());
} catch (Exception var14) {
throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
} finally {
ErrorContext.instance().reset();
try {
reader.close();
} catch (IOException var13) {
;
}
}
return var5;
}
其中最重要的是 XMLConfigBuilder 的 parse 方法,代码如下:
public class XMLConfigBuilder extends BaseBuilder {
public Configuration parse() {
if (this.parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
} else {
this.parsed = true;
this.parseConfiguration(this.parser.evalNode("/configuration"));
return this.configuration;
}
}
private void parseConfiguration(XNode root) {
try {
Properties settings = this.settingsAsPropertiess(root.evalNode("settings"));
this.propertiesElement(root.evalNode("properties"));
this.loadCustomVfs(settings);
this.typeAliasesElement(root.evalNode("typeAliases"));
this.pluginElement(root.evalNode("plugins"));
this.objectFactoryElement(root.evalNode("objectFactory"));
this.objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
this.reflectorFactoryElement(root.evalNode("reflectorFactory"));
this.settingsElement(settings);
this.environmentsElement(root.evalNode("environments"));
this.databaseIdProviderElement(root.evalNode("databaseIdProvider"));
this.typeHandlerElement(root.evalNode("typeHandlers"));
this.mapperElement(root.evalNode("mappers"));
} catch (Exception var3) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + var3, var3);
}
}
// ...省略...
parse 方法最终要返回一个 Configuration 对象,构建 Configuration 对象的建造过程都在 parseConfiguration 方法中,这也就是 Mybatis 解析 XML配置文件 来构建 Configuration 对象的主要过程
所以 XMLConfigBuilder 是建造者 SqlSessionFactoryBuilder 中的建造者,复杂产品对象分别是 SqlSessionFactory 和 Configuration
策略模式: 有一个功能有多种方案可以选择的场景;
应用场景举例:
容错恢复机制
容错恢复机制是应用程序开发中非常常见的功能。那么什么是容错恢复呢?简单点说就是:程序运行的时候,正常情况下应该按照某种方式来做,如果按照某种方式来做发生错误的话,系统并不会崩溃,也不会就此不能继续向下运行了,而是有容忍出错的能力,不但能容忍程序运行出现错误,还提供出现错误后的备用方案,也就是恢复机制,来代替正常执行的功能,使程序继续向下运行。
举个实际点的例子吧,比如在一个系统中,所有对系统的操作都要有日志记录,而且这个日志还需要有管理界面,这种情况下通常会把日志记录在数据库里面,方便后续的管理,但是在记录日志到数据库的时候,可能会发生错误,比如暂时连不上数据库了,那就先记录在文件里面,然后在合适的时候把文件中的记录再转录到数据库中。
对于这样的功能的设计,就可以采用策略模式,把日志记录到数据库和日志记录到文件当作两种记录日志的策略,然后在运行期间根据需要进行动态的切换。
Spring中的策略模式
Spring的事务管理机制就是典型的策略模式,Spring事务策略是通过PlatformTransactionManager接口实现的,它是整个Spring事务的核心。它是对事务策略的一个高度抽象,不依赖于任何具体的事务策略,而对于底层的具体的事务策略它相应的有不同的实现类。而对于不同的事务策略的切换通常由Spring容器来负责管理,应用程序既无须与具体的事务API耦合,也无须与特定的实现类耦合而将应用和持久化技术,事务API彻底分离开来
SpringMVC策略模式
对于某一个点有多种不同的处理策略; 根据情况的不同我们如何优雅的调用这些策略呢?
找到实现策略接口的 所有策略实现实例
// 传入ApplicationContext上下文和策略接口的Class类型
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
// 相应组件的类名
String key = strategyInterface.getName();
// 从property中获取当前策略接口实现类的类名集合
String value = defaultStrategies.getProperty(key);
if (value != null) {
// 获取策略接口所有实现类的类名
String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
List<T> strategies = new ArrayList<T>(classNames.length);
for (String className : classNames) {
try {
// 创建相应实现类的bean,并放入集合中
Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
Object strategy = createDefaultStrategy(context, clazz);
strategies.add((T) strategy);
}
catch (ClassNotFoundException ex) {
throw new BeanInitializationException(
"Could not find DispatcherServlet's default strategy class [" + className +
"] for interface [" + key + "]", ex);
}
catch (LinkageError err) {
throw new BeanInitializationException(
"Error loading DispatcherServlet's default strategy class [" + className +
"] for interface [" + key + "]: problem with class file or dependent class", err);
}
}
// 返回策略接口实现类的集合
return strategies;
}
else {
return new LinkedList<T>();
}
}
* Return the default strategy object for the given strategy interface.
从返回的实现策略接口的实现类中,返回第一个;
protected <T> T getDefaultStrategy(ApplicationContext context, Class<T> strategyInterface) {
List<T> strategies = getDefaultStrategies(context, strategyInterface);
if (strategies.size() != 1) {
throw new BeanInitializationException(
"DispatcherServlet needs exactly 1 strategy for interface [" + strategyInterface.getName() + "]");
}
return strategies.get(0);
}
应用场景一: 它初始化了一个默认的本地化处理组件
private void initLocaleResolver(ApplicationContext context) {
try {
this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);
if (logger.isDebugEnabled()) {
logger.debug("Using LocaleResolver [" + this.localeResolver + "]");
}
}
catch (NoSuchBeanDefinitionException ex) {
// We need to use the default.
this.localeResolver = getDefaultStrategy(context, LocaleResolver.class);
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate LocaleResolver with name '" + LOCALE_RESOLVER_BEAN_NAME +
"': using default [" + this.localeResolver + "]");
}
}
}
应用场景二:
springMVC在决定request的media types时也用到了策略模式。其中的ContentNegotiationManager是最核心的一个类,其中有一个方法我们可以重点来看一下:
优雅的遍历寻找合适的处理策略:
@Override
// 处理请求的mediaTypes
public List<MediaType> resolveMediaTypes(NativeWebRequest request) throws HttpMediaTypeNotAcceptableException {
// 遍历绑定的strategy来处理请求,其中ContentNegotiationStrategy是一个接口,它的实现类包含了多种决定mediaTypes的策略
for (ContentNegotiationStrategy strategy : this.strategies) {
// 如果某一策略实现类识别的请求的mediaTypes,则返回,未识别则继续遍历
List<MediaType> mediaTypes = strategy.resolveMediaTypes(request);
if (mediaTypes.isEmpty() || mediaTypes.equals(MEDIA_TYPE_ALL)) {
continue;
}
return mediaTypes;
}
return Collections.emptyList();
}
总结
从上面两个简单的例子中我们可以看到,使用策略模式的实现方式是:
定义策略接口 -> 实现不同的策略类 -> 利用多态或其他方式调用策略
从springMVC处理request的media types中,我们又可以学到:
当我们遇到的问题时,如果无法事先知道哪种处理方式合适,可以使用策略模式。当某一种策略模式匹配时,返回正确结果,以此解决问题
观察者设计模式:实现组件间解耦
类和类之间的关系,不涉及到继承,学的时候应该 记得归纳。观察者模式很好理解,类似于邮件订阅和RSS订阅,当我们浏览一些博客或wiki时,经常会看到RSS图标,就这的意思是,当你订阅了该文章,如果后续有更新,会及时通知你。其实,简单来讲就一句话:当一个对象变化时,其它依赖该对象的对象都会收到通知,并且随着变化!对象之间是一种一对多的关系
代码的实现:
多个组件向观察中心发送自己的状态消息: 观察中心进行相对应的处理;
对线程的运行过程的 ---提交事件消息--- > 观察中心
todo 对Runnable 接口的扩充
扩充了甚麽呢?
1. Runnable 在运行过程中的运行时可能发生的事件;
public abstract class ObservableRunnable implements Runnable {
final protected LifeCycleListener lifeCycleListener;
public ObservableRunnable(final LifeCycleListener lifeCycleListener) {
this.lifeCycleListener = lifeCycleListener;
}
//通知我的状态已经改变;
protected void notifyChange(final RunnableEvent event){
lifeCycleListener.onEvent(event);
}
//todo
public enum RunnableState{
RUNNING,ERROR,DONE
}
public static class RunnableEvent{
private final RunnableState state;
private final Thread thread;
private Throwable throwable;
public RunnableEvent(RunnableState state, Thread thread, Throwable throwable) {
this.state = state;
this.thread = thread;
this.throwable = throwable;
}
public RunnableState getState() {
return state;
}
public Thread getThread() {
return thread;
}
public Throwable getThrowable() {
return throwable;
}
}
}
todo 事件通知中心处 : 事件通知提交的过程是线程安全的(阻塞的);
public class ThreadLifeCycleObserver implements LifeCycleListener {
private final Object lock=new Object();
@Override
public void onEvent(ObservableRunnable.RunnableEvent event) {
synchronized (lock){
System.out.println("我是观察者中心,我接收到消息:"+"thr runnable ["+ event.getThread().getName()+"] data changed and state is [" +
event.getState()+"]");
if(event.getThrowable()!=null){
System.out.println("我是观察者中心,我接收到消息:"+"thr runnable ["+ event.getThread().getName()+" run failed ");
event.getThrowable().printStackTrace();
}
}
}
}
最后是: 线程在处理自己的事件过程中 ----> 向观察者中心 提交运行的状态;
public static void main(String[] args) {
CreateThreadRegister(Arrays.asList("1", "2", "3"), new ThreadLifeCycleObserver());
}
public static void CreateThreadRegister(List<String> ids, LifeCycleListener lifeCycleListener) {
if (ids == null || ids.isEmpty())
return;
ids.stream().forEach(id -> new Thread(new ObservableRunnable(lifeCycleListener) {
@Override
public void run() {
try {
//调用抽象类中的方法;
notifyChange(new RunnableEvent(RunnableState.RUNNING, Thread.currentThread(), null));
System.out.println("query for the id" + id);
Thread.sleep(1000);
notifyChange(new RunnableEvent(RunnableState.DONE, Thread.currentThread(), null));
} catch (Exception e) {
notifyChange(new RunnableEvent(RunnableState.ERROR, Thread.currentThread(), e));
}
}
}).start());
}
一个对象 A的改变,引起其他所有对象 ( 崇拜A的小迷弟 )的响应的处理;
中心处 维护着自己的 一个粉丝 队列;
import java.util.ArrayList;
import java.util.List;
public class Subject {
// todo
private List<Observer> observers =new ArrayList<>();
private int state;
public int getState() {
return state;
}
public void attach(Observer new_observer){
observers.add(new_observer);
}
public void setState(int state) {
if(this.state==state)
return;
this.state = state;
notifyAllObserver();
}
private void notifyAllObserver(){
observers.stream().forEach(Observer::update);
}
}
public abstract class Observer {
protected Subject subject;
public abstract void update() ;
public Observer(Subject subject) {
this.subject=subject;
this.subject.attach(this);
}
}
public class BinaryObserver extends Observer {
public BinaryObserver(Subject subject) {
super(subject);
}
@Override
public void update() {
System.out.println("Binary String:"+Integer.toBinaryString(subject.getState()));
}
}
public class OctalObserver extends Observer {
public OctalObserver(Subject subject) {
super(subject);
}
@Override
public void update() {
System.out.println("Octal String:"+Integer.toOctalString(subject.getState()));
}
}
测试:
public class Test {
public static void main(String[] args) {
final Subject subject=new Subject();
new BinaryObserver(subject);
new OctalObserver(subject);
System.out.println("====================================");
subject.setState(100);
System.out.println("====================================");
subject.setState(666);
}
}
应用场景: 做应用于组件中生命周期的观察控制;
Tomcat中观察者模式也有多处使用,前面讲的控制组件生命周期的Lifecycle就是这 种模式的体现,还有对Servlet实例的创建、Session的管理、Container等都是同样的原理。 下面主要看一下Lifecycle的具体实现。
Swing中组件的监听器;都是使用了观察者设计模式;
模板模式:
应用场景:
AQS
在之前写的一篇文章里面有 AQS-->ReentratLock 中讲解到 AQS 同步器 抛出了一个模板方法 tryRelease tryLock 释放锁和上锁的方式由子类来自定义来实现. 例如( 共享锁的独占锁的 释放和上锁的 逻辑就不相同;)
mybatis 中的BaseExecutor 实现了提供缓存管理和事务管理的基本功能 , 同时抛出了一个模板 由子类来实现数据库的相关操作;
责任链设计模式:
有多个对象,每个对象持有对下一个对象的引用,这样就会形成一条链,请求在这条链上传递,直到某一对象决定处理该请求。但是发出者并不清楚到底最终那个对象会处理该请求,所以,责任链模式可以实现,在隐瞒客户端的情况下,对系统进行动态的调整。先看看关系图
处理者的共同的特点: 拥有下一个处理者
public abstract class AbstractHandler {
private Handler handler;
public Handler getHandler() {
return handler;
}
public void setHandler(Handler handler) {
this.handler = handler;
}
}
public interface Handler {
public void operator();
}
处理的实例:
public class MyHandler extends AbstractHandler implements Handler {
private String name;
public MyHandler(String name) {
this.name = name;
}
@Override
public void operator() {
System.out.println(name+"deal!");
if(getHandler()!=null){
getHandler().operator();
}
}
}
测试:
public class Main {
public static void main(String[] args) {
MyHandler h1 = new MyHandler("h1");
MyHandler h2 = new MyHandler("h2");
MyHandler h3 = new MyHandler("h3");
h1.setHandler(h2);
h2.setHandler(h3);
h1.operator();
}
}
应用实例:
SpringMVC 中的应用:
HandlerExecutionChain
其中我们可以看到,在springMVC中,DispatcherServlet这个核心类中使用到了HandlerExecutionChain这个类,他就是责任链模式实行的具体类。在DispatcherServlet的doDispatch这个方法中,我们可以看到它贯穿了整个请求dispatch的流程:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
获取该请求的handler,每个handler实为HandlerExecutionChain,它为一个处理链,负责处理整个请求
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
责任链执行预处理方法,实则是将请求交给注册的请求拦截器执行
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
实际的执行逻辑的部分,也就是你加了@RequestMapping注解的方法
实际上是 责任链中得到DefaultServletHttpRequestHandler 处理请求;
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
责任链执行后处理方法,实则是将请求交给注册的请求拦截器执行
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
处理返回的结果,触发责任链上注册的拦截器的AfterCompletion方法,其中也用到了HandlerExecutionChain注册的handler来处理错误结果
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
触发责任链上注册的拦截器的AfterCompletion方法
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
从上面的代码中我们可以看到,HandlerExecutionChain主要负责请求的拦截器的执行和请求的处理,但是他本身不处理请求,只是将请求分配给在链上注册的处理器执行,这是一种责任链的实现方式,减少了责任链本身与处理逻辑之间的耦合的同时,规范了整个处理请求的流程,下面我们看一下上面代码中涉及到的方法在类中对应的代码。
HandlerExecutionChain调用interceptors进行对请求的预处理
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors= getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
HandlerExecutionChain调用interceptors进行对请求的后处理
/**
* Apply postHandle methods of registered interceptors.
*/
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = interceptors.length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(request, response, this.handler, mv);
}
}
}
HandlerExecutionChain调用interceptors进行对请求的异常处理
/**
* Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
* Will just invoke afterCompletion for all interceptors whose preHandle invocation
* has successfully completed and returned true.
*/
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)
throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
try {
interceptor.afterCompletion(request, response, this.handler, ex);
}
catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
}
HandlerExecutionChain是一个人际关系比较好的人,他可以调用多个朋友来帮他处理一些事情;
责任链模式可以很好的将原本耦合的顺序过程处理的代码和逻辑,解耦成执行的顺序逻辑,和一个个相对应的处理器(责任人),对应的责任链只需要关心责任处理的顺序,而不需要关心具体的处理逻辑,将这些逻辑交给注册的责任人去处理。从springMVC的源码中,我们可以看到这一设计模式的应用,将原本复杂的请求处理逻辑表现的清楚明白。
mybatis 中的interceptorchain
Interceptor、InterceptorChain 来生成mybatis的四大核心: paramHandler , executor ,statementhandler , resulthandler
命令模式:
命令模式比较简单,但是在项目中使用是非常频繁的,封装性非常好,因为它
把请求方(Invoker)和执行方(Receiver)分开了
,扩展性也有很好的保障。但是,命令模式也是有缺点的,如果需要扩展命令,就需要新增加Command类的子类,如果要新增的子类数量很多,那么是否使用命令模式就需要考虑了。
简单的代码实现方式:
public static void main(String[] args) {
// 定义张三为接头人
Invoker zhangsan = new Invoker();
System.out.println("----------------客户要求增加一项需求----------------");
// 客户下命令
Command command = new AddRequirementCommand();
// 接头人接受命令
zhangsan.setCommand(command);
// 接头人执行命令
zhangsan.action();
}
项目组分成了三个组,每个组要接受增删改的命令
public abstract class Group {
public abstract void add();
public abstract void delete();
public abstract void change();
public abstract void find(); // 客户要和某个小组沟通,必须先找到对应的小组
public abstract void plan(); // 客户要求某小组列出执行计划
}
/**
* @description: 美工组
*/
public class PageGroup extends Group {
@Override
public void add() {
System.out.println("客户要求增加一个页面...");
}
@Override
public void delete() {
System.out.println("客户要求删除一个页面...");
}
@Override
public void change() {
System.out.println("客户要求修改一个页面...");
}
@Override
public void find() {
System.out.println("找到美工组...");
}
@Override
public void plan() {
System.out.println("客户要求列出页面变更计划...");
}
}
/**
* @description: 需求组
*/
public class RequirementGroup extends Group {
@Override
public void add() {
System.out.println("客户要求增加一项需求...");
}
@Override
public void delete() {
System.out.println("客户要求删除一项需求...");
}
@Override
public void change() {
System.out.println("客户要求修改一项需求...");
}
@Override
public void find() {
System.out.println("找到需求组...");
}
@Override
public void plan() {
System.out.println("客户要求列出需求变更计划...");
}
}
/**
* @description: 代码组
*/
public class CodeGroup extends Group {
@Override
public void add() {
System.out.println("客户要求增加一个功能...");
}
@Override
public void delete() {
System.out.println("客户要求删除一个功能...");
}
@Override
public void change() {
System.out.println("客户要求修改某个功能...");
}
@Override
public void find() {
System.out.println("找到代码组...");
}
@Override
public void plan() {
System.out.println("客户要求列出代码变更计划...");
}
}
封装命令
public abstract class Command {
protected RequirementGroup rg = new RequirementGroup();
protected PageGroup pg = new PageGroup();
protected CodeGroup cg = new CodeGroup();
// 只要一个方法,你要我做什么事情
public abstract void execute();
}
public class AddRequirementCommand extends Command {
@Override
public void execute() {
// 找到需求组
super.rg.find();
// 增加一份需求
super.rg.add();
// 页面要增加
super.pg.add();
// 功能也要增加
super.cg.add();
//给出计划
super.rg.plan();
}
}
//todo 将任务封装成任务接口 然后通过这个类来执行调用任务
public class Invoker {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void action() {
this.command.execute();
}
}
命令模式的应用场景:
2 Transactional behavior(原子事务行为)
借助command模式,可以简单地实现一个具有原子事务的行为。当一个事务失败时,往往需要回退到执
行前的状态,可以借助command对象保存这种状态,简单地处理回退操作。
6 Thread pools(线程池)
通常一个典型的线程池实现类可能有一个名为addTask()的public方法,用来添加一项工作任务到任务
队列中。该任务队列中的所有任务可以用command对象来封装,通常这些command对象会实现一个通用的
接口比如java.lang.Runnable。
Networking
通过网络发送command命令到其他机器上运行。
Parallel Processing(并发处理)
当一个调用共享某个资源并被多个线程并发处理时