设计模式之结构型1
设计模式之结构型1
1. 代理模式
总的来说,根据代理类的创建时机和创建的方式不同,可以将代理分为静态代理和动态代理。
代理模式属于开闭原则的典型应用。
代理对象存在的价值主要用于拦截对真实业务对象的访问;
代理对象应该具有和目标对象相同的方法,即实现共同的接口或继承于同一个类;
代理对象应该是目标对象的增强。
代理模式包含如下几个角色:
- 客户端:客户端面向接口编程,使用代理角色完成某项功能。
- 抽象主题:一般实现为接口,是对(被代理对象的)行为的抽象。
- 被代理角色(目标类):直接实现上述接口,是抽象主题的具体实现。
- 代理角色(代理类):实现上述接口,是对被代理角色的增强。
1.1 静态代理
以电影院播放电影为例,核心接口功能是播放电影,但是电影院作为代理,还可以播放广告,出售零食。
-
抽象主题(接口)
public interface Movie{ void play(); }
-
被代理角色(目标类)与代理角色(代理类)
- 真正实现Movie接口的类
public class RealMovie implements Movie{ @override public void play(){ System.out.println("您正在观看电影《哈利波特之凤凰社》"); } }
- 代理类
package com.frank.test; public class Cinema implements Movie { RealMovie movie; public Cinema(RealMovie movie) { super(); this.movie = movie; } @Override public void play() { guanggao(true); // 代理类的增强处理 movie.play(); // 代理类把具体业务委托给目标类,并没有直接实现 guanggao(false); // 代理类的增强处理 } public void guanggao(boolean isStart){ if ( isStart ) { System.out.println("电影马上开始了,爆米花、可乐、口香糖9.8折,快来买啊!"); } else { System.out.println("电影马上结束了,爆米花、可乐、口香糖9.8折,买回家吃吧!"); } } }
-
客户端
public class ProxyTest{ public static void main(String[] args){ RealMovie realmovie = new RealMovie(); Movie movie = new Cinema(realmovie); movie.play(); } }
1.2 动态代理
动态代理可以在程序运行期间,根据需要,动态地创建代理类及其实例来完成具体的功能。
-
抽象主题(接口)
public interface Subject{ public void doSomething(); }
-
被代理角色
我们要有一个真正的实现这个Subject接口的类,以便代理
import class RealSubject implements Subject{ public void doSomething(){ System.out.println("call doSomething()"); } }
-
代理角色(代理类)与客户端
动态代理中,代理类及其实例是程序自动生成的,因此我们不需要手动去创建代理类。在Java的动态代理机制中,
InvocationHandler(Interface)
接口和Proxy(class)
类是实现我们动态代理所必须用到的。事实上,Proxy通过使用InvocationHandler
对象生成具体的代理对象。import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * Title: InvocationHandler的实现 * Description:每个代理的实例都有一个与之关联的InvocationHandler * 实现类,如果代理方法被调用,那么代理便会通知和转发给内部的InvocationHandler */ public class ProxyHandler implements InvocationHandler{ private Object proxied; //被代理对象 public ProxyHandler(Object proxied){ this.proxied = proxied; } public Object invoke(Object proxy,Method,Object[] args) throws Throwable{ //在转调具体目标对象之前,可以执行一些功能处理 System.out.printn("前置增强处理:yoyoyo..."); //在转调具体目标对象的方法(三要素:实例对象+实例方法+实例方法的参数) Object obj = method.invoke(proxied,args); //在转调具体目标对象之后,可以执行一些功能处理 System.out.println("后置增强处理:hahaha..."); return obj; } }
-
创建代理对象
在实现了
InvocationHander
接口后,我们就可以创建代理对象了。在Java的动态代理机制中,我们使用Proxy类的静态方法newProxyInstance
创建代理对象import java.lang.reflect.Proxy; import cn.handler.ProxyHandler; import cn.impl.RealSubject; import cn.inter.Subject; public class Test{ public static void main(String[] args){ //真实对象real Subject real = new RealSubject(); //生成real的代理对象 Subject proxySubject = (Subject)Proxy.newProxyInstance( Subject.class.getClassLoader(),new Class[]{Subject.class}, new ProxyHandler(real)); proxySubject.doSomething(); System.out.println("代理对象的类型:"+proxySubject.getClass().getName()); System.out.println("代理对象所在类的父类型:"+proxySubject.getClass().getGemericSuperclass()); } }
-
JDK中的InvovationHandler接口与Proxy类
-
InvocationHandler接口
每个代理的实例都有一个与之关联的
InvocationHandler
实现类,如果代理的方法被调用,那么代理便会通知和转发给内部的InvocationHandler
实现类,由它决定处理。public interface InvovationHandler{ public Object invoke(Object proxy,Method method,Object[] args) throws Throwable; }
InvocationHandler中的invoke()方法决定了怎样处理代理传递过来的方法调用。
-
Proxy类
JDK通过Proxy的静态方法newProxyInstance动态地创建代理,该方法的声明入下:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
事实上,Proxy动态产生的代理对象调用目标方法时,代理对象会调用InvocationHandler实现类,所以InvocationHandler是实际执行者。
-