设计模式之适配器模式 (八)

说到适配器模式,顾名思义,就像我们平时使用的手提电脑的电源适配器,经过适配,它可以为我们的手提电脑提供一个稳定适合的低压直流电。

定义:将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。——Gang of Four

一般适配器模式有三种实现:

1. 类适配器 使用继承的方式实现

比如之前讲过的观察者模式里,观察者都必须实现一个观察者接口才可以被通知,但是我现在有一个类无法改动它的源码(或是不能实现接口),那该怎么办呢,假设有一个HashMap类,我需要在被观察者做更新的时候,调用HashMap类中的一个clear()方法清空一下,那HashMap又不可能去继承一个观察者接口,这时候就需要用到适配器了。

package test;

import java.util.HashMap;
import java.util.Observable;
import java.util.Observer;

public class HashAdapter<K, V> extends HashMap<K, V> implements Observer{

	@Override
	public void update(Observable o, Object arg) {
		super.clear();
	}
	
}

我们只需要继承想实现接口的那个类,再实现你想要实现的接口即可。这样一来,只需要将这个Hash适配器类加入到观察者列表,等到通知的时候自动会调用父类的clear方法,从而达到我们的目的了。

2. 对象适配器 使用组合的方式实现

package test;

import java.util.HashMap;
import java.util.Observable;
import java.util.Observer;

public class Adapter implements Observer {

	HashMap<Object, Object> hash = new HashMap<>();

	public Adapter(HashMap<Object, Object> hash) {
		this.hash = hash;
	}

	@Override
	public void update(Observable o, Object arg) {
		hash.clear();
	}
}

我们可以看出来,当有多个类需要被适配时,只需要修改Adapter内部,本来我们是继承被适配的类,然后利用继承的特性调用super实现被适配的方法,间接让被适配的类实现了某个需要实现的接口,现在我们只需要持有被适配类的一个应用,在构造函数里接收它,利用它来实现我们需要实现的方法,看起来比类适配器更灵活了一点?使用对象适配器还能适配多个类,解决了类适配器只能适配单个类(JAVA单继承的特性)的问题。

3. 缺省适配器 

缺省适配器在我做一个模仿天猫官网项目中有接触到,在我写一个关于权限拦截的功能的时候,需要写一个拦截器。

public class LoginInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        HttpSession session = request.getSession();
        String contextPath = session.getServletContext().getContextPath();
        String [] ignorePath = new String []{
            "home","register","login","product","checkLogin","loginAjax","category","search"};
        String url = request.getRequestURI();
        url = StringUtils.remove(url , contextPath);
        if (url.startsWith("/fore")){
            String method = StringUtils.substringAfterLast(url,"/fore");
            List<String > a = Arrays.asList(ignorePath);
            if (!a.contains(method)){
                User user = (User) session.getAttribute("user");
                if (null == user){
                    response.sendRedirect("login");
                    return false;
                }
            }

        }

        return true;
    }
}

这就是当时写的拦截器类了,由于我只需要在进入servlet前进行拦截,所以只需要实现preHandle方法即可,这个拦截器还有很多方法,例如postHandle,在准备渲染视图时的方法,可以在里面设置一些全局变量,或是对一些变量做修改,都可以在这个方法里实现,这里不多介绍拦截器。可以看出,这里我不是实现拦截器接口,而是继承了一个拦截器适配器,进入这个拦截器适配器看看它为我们做了什么?

public abstract class HandlerInterceptorAdapter implements AsyncHandlerInterceptor {
    public HandlerInterceptorAdapter() {
    }

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true;
    }

    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    }

    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    }

    public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    }
}

这个适配器帮我们实现了拦截器的接口,并默认实现了所有的方法(返回一个默认值),这样我们在写拦截器的时候,像刚刚说到的,我只想拦截进入servlet之前的操作,换句话讲我只实现一个preHandle方法,拦截器接口的其他方法我都不用去实现它,这个时候缺省适配器帮我们解决了这个问题,这样我的拦截器就不用为了编译通过,而去实现一些空方法放在那边,专注实现需要实现的那一个方法即可。这个缺省适配器也满足了开篇前言所说的,最小接口原则。

注:由于我的水平有限,有些地方说的可能有问题?欢迎大家指出,互相讨论互相学习进步!

猜你喜欢

转载自blog.csdn.net/qq_41737716/article/details/80540872
今日推荐