装饰者模式:
1、java设计了汽车开发约定,即接口ICar,有start、run、stop三个方法:
interface ICar{ start run stop}
public interface ICar {
public String start(int a,int b);
public void run();
public void stop();
}
2、其实现类为 GoogleCar:
class GoogleCar implements ICar{}
//相当于mysql驱动包,谷歌汽车开发人员实现类
public final class GoogleCar implements ICar{
@Override
public void start() {
System.out.println("控制谷歌的汽车启动");
//调用谷歌汽车提供的C语言函数
}
@Override
public void run() {
System.out.println("控制谷歌的汽车运行");
}
@Override
public void stop() {
System.out.println("控制谷歌的汽车停止");
}
}
3、希望在将GoogleCar接入到生态圈平台时,增强汽车启动功能
4、装饰者模式
场景:二次开发的时候,在无法获取到源码,无法使用继承前提下,要对已经存在对象上的功能进行增强.
前提:可以获取到被装饰的对象GoogleCar实现的所有接口
实现思路:自定义一个装饰类实现ICar接口,为自定义装饰类传递被装饰的对象
public class MyCar implements ICar{
ICar car;
public MyCar(ICar car) {
this.car=car;
}
@Override
public void start() {
System.out.println("检查天气是否良好");
System.out.println("检查路况是否拥堵");
car.start();
}
@Override
public void run() {
car.run();
}
@Override
public void stop() {
car.stop();
}
}
测试代码:
public class TestCar {
public static void main(String[] args) {
ICar car=new MyCar(new GoogleCar());
car.start();
car.run();
car.stop();
}
}
弊端:如果被实现的接口中的方法过多,装饰类中的方法过多冗余
动态代理模式
原理:通过虚拟机在内存中创建类似MyCar.class文件
要创建MyCar.class文件告诉虚拟机:
1_被创建的字节码文件上应该有多少方法
2_被创建的字节码上的方法如何来实现
public class TestCar {
public static void main(String[] args) {
//1param: 固定值: 告诉虚拟机用哪个字节码加载器加载内存中创建出的字节码文件
//2param: 告诉虚拟机内存中正在被创建的字节码文件中应该有哪些方法
//3param: 告诉虚拟机正在被创建的字节码上的各个方法如何处理
ICar car=(ICar)Proxy.newProxyInstance(TestCar.class.getClassLoader(), GoogleCar.class.getInterfaces(),new InvocationHandler() {
//method:代表正在执行的方法
//args:代表正在执行的方法中的参数
//Object:代表方法执行完毕之后的返回值
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//经过测试得知:method代表当前正在执行的每个方法
//System.out.println(method.getName());
//执行当前的方法
//method.invoke(new GoogleCar(), args);
//代表每个方法执行完毕之后返回对象
Object obj=null;
if(method.getName().equalsIgnoreCase("start")){
System.out.println("检查天气是否良好");
//打印args中的内容
System.out.println(Arrays.toString(args));
obj=method.invoke(new GoogleCar(), args);
System.out.println("检查路况是否拥堵");
}else{
obj=method.invoke(new GoogleCar(), args);
}
return obj;
}
});
String cc=car.start(1,4);
System.out.println(cc);
car.run();
car.stop();
}
}
案例:使用动态代理解决中文乱码问题
步骤
1、new DynamicWeb Project >Index.html
<body>
<form action="/ProxyDemo/ServletDemo" method="post">
<h3>使用post方式提交</h3>
<input type="text" name="username" /><br>
<input type="submit" value="提交" /><br>
</form>
<form action="/ProxyDemo/ServletDemo" method="get">
<h3>使用get方式提交</h3>
<input type="text" name="username" /><br>
<input type="submit" value="提交" /><br>
</form>
</body>
2、ServletDemo:无论是在post/get方法,执行以下语句不存在中文乱码问题
String um=request.getParameter("username");
System.out.println(um);
3、在过滤器中,为request上的getParameter()功能进行增强
思路:
>判断当前的请求是get/post request.getMethod();
>>如果是post, 设置一句话: request.setCharacterEncoding(“utf-8”);放行
>>如果是get,调用原先的String v=request.getParameter(name);将v进行转码,放行
public void doFilter(ServletRequest req, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// 让req对象转换为HttpServletRequest
HttpServletRequest request = (HttpServletRequest) req;
// 让jdk在内存中生成代理对象:增强了request对象上的getParameter(name)API
HttpServletRequest requestProxy = (HttpServletRequest) Proxy.newProxyInstance(
EncodingFilter.class.getClassLoader(), request.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 = request.getMethod();
if ("get".equalsIgnoreCase(md)) {
// get方式请求
// 调用request对象上的getParameter方法
String str = (String) method.invoke(request, args);
// 转码
String strs = new String(str.getBytes("UTF-8"),"UTF-8");
return strs;
} else {
// post请求方式
request.setCharacterEncoding("UTF-8");
obj = method.invoke(request, args);
}
} else {
obj = method.invoke(request, args);
}
return obj;
}
});
System.out.println(requestProxy.hashCode());
chain.doFilter(requestProxy, response);
}