一、单例模式:只有一个实例的对象
代码:
public class SingleTemp{ private SingleTemp(){ } public static SingleTemp single = new SingleTemp(); public static SingleTemp getInstance(){ return single; } }
二、装饰者模式:增强原始代码的功能,在不改动原始代码的基础上
继承也可以实现
原始代码:
public interface ICar { public void start(); public void run(); public void stop(); } public class GoogleCar implements ICar{ @Override public void start(){ ... } @Override public void run(){ ... } @Override public void stop(){ ... } }
继承代码:
public class MyCar extends GoogleCar{ @Override public void start(){ //增强代码.... super.start(); //增强代码.... } } public class Test{ public static void main(String[] args){ ICar car=new MyCar(); car.start(); } }
很完美的实现我们想要的增强功能,且没有改动源代码。但是很多时候源代码(源代码被final修饰)是不允许继承的话,继承就不能实现了。
这就要用到装饰者模式
装饰者模式的场景:无法获取源码,无法使用继承,要增强已经存在对象上的功能
前提:可以获取到被装饰的对象(GoogleCar)实现的所有接口(ICar)
代码:
public final class GoogleCar implements ICar{ @Override public void start(){ ... } @Override public void run(){ ... } @Override public void stop(){ ... } } public class MyCar implements ICar{ ICar car; public MyCar(ICar car){ this.car=car; } @Override public void start(){ //增强代码.... this.car.start(); //增强代码.... } @Override public void run(){ //增强代码.... this.car.run() //增强代码.... } @Override public void stop(){ this.car.stop() } } public class Test{ public static void main(String[] args){ ICar car=new MyCar(new GoogleCar()); car.start(); } }
弊端:如果被实现的接口中的方法过多,装饰类中的方法就会冗余,一些不需要增强的方法需要重写其方法
三、动态代理(Proxy.newProxyInstance)
原理:通过虚拟机在内存中创建字节码文件
1、通过虚拟机在内存中创建字节码文件,字节码文件的内容是:增强功能的类中的所有方法(是指类实现的所有接口中的方法,不包含类自身的方法)
2、通过字节码加载器把字虚拟机在内存中创建的节码文件加载成字节码对象
3、虚拟机修改内存中的字节码对象中的方法具体处理
具体代码如下:
public class Test{ public static void main(String[] args){ //1.根据GoogleCar字节码文件获取其实现的所有接口 //2.获取接口中所有的方法 /* Class[] clazz=GoogleCar.class.getInterfaces(); for(Class cla : clazz){ Method[] mds= cla.getMethods(); for(Method method : mds){ method.getName(); } } */ /* 参数1:固定值(字节码加载器加载内存中字节码文件,创建字节码对象) 参数2:创建字节码对象中有哪些接口 参数3:创建字节码对象中接口的方法的具体处理 */ ICar car = (ICar)Proxy.newProxyInstance(Test.class.getClassLoader,GoogleCar.class.getInterfaces() ,new InvocationHandler(){ /* method:正在执行的方法 args:正在执行的方法中的参数 Object:方法执行后的返回值 */ @Override public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{ Object obj = null; if(method.getName().equalsIgnoreCase("start")){ //增强代码...... } // 执行当前方法 obj = method.invoke(new GoogleCar(),args); return obj; } }); car.start(); car.run(); car.stop(); } }
4、动态代理解决网站乱码问题(实际就是Request对象的getParameter()方法增加字符串编码转换或设置字符串的编码Code)
①、newDynamicWeb Project -->index.html
<h1>post方式提交中文</h1> <form action="/ServletDemo" method="post"> User:<input type="" name="username"/><br/> <input type="submit"/> </form> <h1>get方式提交中文</h1> <form action="/ServletDemo" method="get"> User:<input type="" name="username"/><br/> <input type="submit"/> </form>
②、ServletDemo
String um=request.getParameter("username");
System.out.println(um);
③、增强Request对象getParameter()方法
public class EncodingFilter implements Filter { public EncodingFilter() { } public void destroy() { } public void init(FilterConfig fConfig) throws ServletException { } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { //将request对象转换为HttpServletRequest final HttpServletRequest req=(HttpServletRequest)request; //让JDK在内存中生成代理对象:增强了req对象上的getParameter(name);API HttpServletRequest myReq=(HttpServletRequest)Proxy.newProxyInstance(EncodingFilter.class.getClassLoader(), req.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object obj=null; if(method.getName().equalsIgnoreCase("getParameter")){ //获取本次请求方式 String md=req.getMethod(); if("get".equalsIgnoreCase(md)){ //get方式的请求 //调用req对象上的getParameter方法 String v=(String)method.invoke(req, args); //转码 String vv=new String(v.getBytes("iso-8859-1"),"utf-8"); return vv; }else{ //post方式的请求 req.setCharacterEncoding("utf-8"); obj=method.invoke(req, args); } }else{ obj=method.invoke(req, args); } return obj; } }); //打印代理对象哈希码 System.out.println(myReq.hashCode()); //将代理对象放行 chain.doFilter(myReq, response); } }
④、过滤器的配置
<filter> <display-name>EncodingFilter</display-name> <filter-name>EncodingFilter</filter-name> <filter-class>xcn.xx.xxx..EncodingFilter</filter-class> </filter> <filter-mapping> <filter-name>EncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>