前言
前面的博文我们已经分别讲述了代理模式,策略模式和委派模式各自的使用及案例实现。
但是三者都写完了,我发现其实我自己都有些混淆了,所以今天特意把他们放在一起看看究竟有什么区别和联系
策略模式:
策略模式是对算法的封装。定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换
优点: 1、算法可以自由切换。 2、避免使用多重条件判断。 3、扩展性良好。
缺点: 1、策略类会增多。 2、所有策略类都需要对外暴露。
场景:
Spring中Aop代理策略createAopProxy(下文讲解)
Spring的对象实例化策略InstantiationStrategy
委派模式:
委派模式的基本作用就是负责任务的调度和分配任务
场景:
- 类加载的双亲委派机制
- SpringMVC的DispatcherServlet
- Spring中bean解析的BeanDefinitionParserDelegate
代理模式:
代理模式为其他对象提供一种代理以控制对这个对象的访问
优点: 1、职责清晰。 2、高扩展性。 3、智能化。
缺点: 1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。 2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。
场景:
- JDK动态代理和CGLIB动态代理
- Spring的AOP
有什么不同
代理和策略:
- 简单代理模式中,代理类知道被代理类的行为,因为代理类与被代理类实现的是同一个接口,因此代理类与被代理类的结构是相同的
- 策略模式中,策略容器并不知道内部策略的详细信息,因为容器并没有实现与内部策略相同的接口,即容器与内部策略只是简单的组合关系,容器只是将内部策略的行为抽取出来,进行了统一的实现。
代理和委派:
- 委派模式的基本目的就是负责任务的调用和分配,和代理模式很像,可以看成是一个特殊的静态代理的全权代理
- 但是代理模式注重过程(),委派模式注重结果(老板不关注任务是怎么完成的,只管把任务交给经理让他去委派调度)。
- 代理模式中,代理类的被代理对象始终不变,而委派模式中委派类的被委托对象可以随时切换。
- 委派模式中委派类相当于全权代理,而不是像代理模式是部分代理
- 也有人理解为代理模式中二者是上下级关系,而委派模式中二者是平级关系
委派和策略:
- 委派模式中委派者和被委派者实现了同一个接口,
- 策略模式中容器只是算法策略的选择切换所在,不需要实现策略接口
总结
我试着在一个简单的故事中,来举例区分一下这些模式的存在场景(有异议请留言讨论,谢谢)
前几天公司所在的地方要拆迁,所以只能搬办公室,大家都得帮忙不是,经理也要去深圳出差,就直接告诉HR让她负责,于是HR就开始分配任务,男生负责搬运东西,女生负责清洁,其他的同学就干干杂物,所以搬家公司一把东西搬到新办公室,大家就听HR指挥了,HR看到灯管要换一下,那么这个任务就要交给男生了,看到玻璃脏了,那么这个任务就要交给女生。
到下午的时候,HR收到了中通快递的短信,可能买了一些新办公室需要的东西,要去快递柜那边拿,我刚好闲着,于是HR把她的短信给我,让我领一下。到了那边,看到快递柜是很大的那种分区的,有中通快递的,有申通快递的,但是取货机是只有一个的,我输了取货码,然后跑到中通快递所在的区,"呯"!,果然这边的快递门开了,好神奇!
分析:
- 分配任务中,HR是委派者,男生女生是被委派者
- 去取快递时,HR是目标对象,我是代理对象,短信是目标对象的引用
- 取快递中,取货机是容器,不同快递的取货码是不同的算法策略
有什么联系
很多设计模式其实在一些优秀的框架中都是混合使用的。
策略和代理:
Spring中Aop代理策略
首先看AopProxyFactory接口类提供了createAopProxy接口,这个是策略模式的接口方法。然后DefaultAopProxyFactory实现了该接口作为策略的实现者。然后ProxyCreatorSupport里面引用了AopProxyFactory,并且提供了get,set方法用来运行时改变策略,这里Spring只实现了DefaultAopProxyFactory这一个策略,如果需要自己也可以写个。
策略模式:DefaultAopProxyFactory里面的createAopProxy的逻辑如下,可以在运行时根据参数决定用Cglib策略还是JDK动态代理策略生成代理类:
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
//如果XML打开了优化开关,或者设置为了代理目标类,或者目前类没有接口
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
//如果有接口,或者通过Proxy.newProxyInstance生成的,则使用jdk动态代理
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
//使用cglib
return new ObjenesisCglibAopProxy(config);
}
else {
//使用jdk动态代理
return new JdkDynamicAopProxy(config);
}
}
AopProxy也是一个策略接口类,具体实现的策略为(代理模式)JdkDynamicAopProxy,CglibAopProxy,ObjenesisCglibAopProxy
策略和委派
Spring中的DispatcherServlet
在DispatcherServlet的初始化中有初始化策略方法 ,会使用默认的处理策略HandlerMapping:
protected void initStrategies(ApplicationContext context) {
//初始化文件上传处理类
initMultipartResolver(context);
//初始化本地化Resolver
initLocaleResolver(context);
//初始化主题Resolver
initThemeResolver(context);
//初始化一些个预处理的HandlerMappings
initHandlerMappings(context);
//
initHandlerAdapters(context);
//初始化异常处理的handler
initHandlerExceptionResolvers(context);
//初始化请求路径转换为ViewName 的Translator
initRequestToViewNameTranslator(context);
//初始化ViewResolvers 这个就是针对视图处理的Resolvers 比如jsp处理Resolvers 或者freemarker处理Resolvers
initViewResolvers(context);
//初始化 主要管理flashmap,比如RedirectAttributes 的属性会放到这个里面,默认使用的是SessionFlashMapManager
initFlashMapManager(context);
}
/**
* Initialize the HandlerMappings used by this class.
* <p>If no HandlerMapping beans are defined in the BeanFactory for this namespace,
* we default to BeanNameUrlHandlerMapping.
*/
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
if (this.detectAllHandlerMappings) {
// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());
// We keep HandlerMappings in sorted order.
OrderComparator.sort(this.handlerMappings);
}
}
else {
try {
HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default HandlerMapping later.
}
}
// Ensure we have at least one HandlerMapping, by registering
// a default HandlerMapping if no other mappings are found.
if (this.handlerMappings == null) {
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
if (logger.isDebugEnabled()) {
logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
}
}
}
策略模式:从源码中我们可以看到,SpringMVC先会从绑定的ApplicationContext中获取对应的HandlerMapping定义,如果没有取到就会调用getDefaultStrategies(context, HandlerMapping.class)从默认策略中获取。
/**
* 请求的分发工作
* @param request
* @param response
*/
private void doDispatch(HttpServletRequest request, HttpServletResponse response) {
//1.获取用户请求的url
String uri = request.getRequestURI();
Handler handler =null;
////2、根据uri 去handlerMapping找到对应的hanler
for(Handler h :handlerMapping){
if(uri.equals(h.getUrl())){
handler = h;
break;
}
}
//3.将具体的任务分发给Method(通过反射去调用其对应的方法)
Object obj = null;
try {
obj = handler.getMethod().invoke(handler.getController(),request.getParameter("mid"));
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
//4、获取到Method执行的结果,通过Response返回出去
// response.getWriter().write();
}
委派模式:DispatcherServlet,前端控制器收到请求后自己不进行处理,而是委托给其他的解析器进行处理,作为统一访问点,进行全局的流程控制。