Java设计模式(一)——代理模式
有高手云:了解设计模式才算是入门级的程序员。
所以为了入门我打算把我学习到的设计模式逐条总结下来。和别人的文章不同,我几乎只提供了测试源码与细节分类。原因是,我相信对于设计来说,你永远无法给出终极答案。不同的人看到会有不同的理解,所以大家一起讨论吧。
一、静态代理
设计测试接口,提供request()方法
package proxy.staticproxy; public interface Service {
void request();
}
Service 接口
创建两个实现类
package proxy.staticproxy; public class UserServiceImpl implements Service { @Override
public void request() {
System.out.println("UserServiceImpl...");
} }
UserServiceImpl
package proxy.staticproxy; public class AdminServiceImpl implements Service { @Override
public void request() {
System.out.println("AdminServiceImpl...");
} }
AdminServiceImpl
创建可以实现代理的抽象类,此抽象类同样实现了Service接口。创建抽象类的目的是为了设计一种可以为指定接口提供代理的模板,用户只要继承此抽象类即可。
package proxy.staticproxy; public abstract class ProxyService implements Service {
private Service serviceImpl; public ProxyService(Service service) {
this.serviceImpl = service;
} @Override
public void request() {
preRequest();
serviceImpl.request();
postRequest();
} abstract void preRequest(); abstract void postRequest(); }
ProxyService
创建两个代理类
package proxy.staticproxy; public class CheckProxyServiceImpl extends ProxyService { public CheckProxyServiceImpl(Service service) {
super(service);
} @Override
void preRequest() {
System.out.println("Check preRequest...");
} @Override
void postRequest() {
System.out.println("Check postRequest...");
} public static void main(String[] args) { }
}
CheckProxyServiceImpl
package proxy.staticproxy; public class ReferProxyServiceImpl extends ProxyService { public ReferProxyServiceImpl(Service service) {
super(service);
} @Override
void preRequest() {
System.out.println("Reference preRequest...");
} @Override
void postRequest() {
System.out.println("Reference postRequest...");
} public static void main(String[] args) {
Service user = new UserServiceImpl();
Service userReferProxy = new ReferProxyServiceImpl(user);
Service userCheckProxy = new CheckProxyServiceImpl(userReferProxy);
userCheckProxy.request();
}
}
ReferProxyServiceImpl
输出结果:
Check preRequest...
Reference preRequest...
UserServiceImpl...
Reference postRequest...
Check postRequest...
二、动态代理
动态代理可以通过JDK或者CGLIB来实现,它是AOP思想的主要具体表现形式之一。
设计测试接口
package proxy.dynamicproxy; public interface Hypnosis {
void hypnosis();
void hypnosis(String s);
}
Hypnosis
编写实现类
package proxy.dynamicproxy; import java.util.Random; public class HypnosisImpl implements Hypnosis { @Override
public void hypnosis() {
try {
Thread.sleep(new Random().nextInt(10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
} @Override
public void hypnosis(String s) {
try {
System.out.println(s);
Thread.sleep(new Random().nextInt(10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
} }
HypnosisImpl
动态代理最令人费解的地方在于如何使用它的InvocationHandler。因为采用了动态编译和反射等技术,对于方法的实现往往不太直观。
package proxy.dynamicproxy; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; public class InvocationHandlerDemo implements InvocationHandler {
private Object target; public InvocationHandlerDemo(Object o) {
target = o;
} /*
* 实现方法的代理逻辑
* 第1个参数表示目标对象的代理对象,通常不调用
* 第2个参数代表接口中的方法,用户通过反射调用,proxy提供实参
* 第3个参数代表传递给方法的实参,用户在定义proxy传递,proxy调用handler时传递
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long startTimer = System.currentTimeMillis();
Object o = method.invoke(target, args);
long endTimer = System.currentTimeMillis();
System.out.println("Run Time:" + (endTimer - startTimer));
return o;
} }
InvocationHandlerDemo
其实对方法Proxy.newProxyInstance()的调用也不太直观,为了方便使用通常我会对它进行包装。
package proxy.dynamicproxy; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy; public class ProxyDemo {
private InvocationHandler h; // 也可以通过setter方法注入handler
public ProxyDemo(InvocationHandler h) {
this.h = h;
} public Object getProxy(Class<?> clazz, Class<?>... interfaceClasses) throws Exception {
if (interfaceClasses.length > 0) {
/*
* 指定InvocationHandler实现代理
* 第1个参数定义代理类的类加载器
* 第2个参数为接口数组
* 第3个参数定义方法处理类
*/
return Proxy.newProxyInstance(clazz.getClassLoader(), interfaceClasses, h);
} else {
throw new Exception("Have to set Interface...");
}
} // 重新包装了代理方法
public Object getProxy(Object o) throws Exception {
return Proxy.newProxyInstance(o.getClass().getClassLoader(), o.getClass().getInterfaces(), h);
} public static void main(String[] args) {
Hypnosis hypnosis = new HypnosisImpl();
InvocationHandler h = new InvocationHandlerDemo(hypnosis);
ProxyDemo demo = new ProxyDemo(h);
try {
Hypnosis hy = (Hypnosis) demo.getProxy(hypnosis);
hy.hypnosis();
hy.hypnosis("i was be hypnosis");
} catch (Exception e) {
e.printStackTrace();
}
}
}
ProxyDemo
如果需要代理的原型对象没有实现任何接口,就必须使用CGLIB。Spring提供了综合解决方案。
三、虚拟代理
虚拟代理是针对后台响应需要时间,而前台又不希望让用户无聊等待而设计的。通过多线程实现,前台加载能快速响应的动作,加载缓慢的动作丢给另外一个线程处理。
设计测试接口
package proxy.virtualproxy; public interface Service {
void response();
}
Service
编写实现类
package proxy.virtualproxy; public class ServiceImpl implements Service {
@Override
public void response() {
System.out.println("服务器正在准备应答...");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("服务器应答完成!");
} }
ServiceImpl
还是通过抽象类来封装代理的模板,与静态代理不同的是需要把原型方法和代理方法独自封装在不同的内部类中。可见,如果原型类的方法比较多,代码就会显得比较臃肿。
package proxy.virtualproxy; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public abstract class ProxyService implements Service {
private Service s; public ProxyService(Service s) {
this.s = s;
} @Override
public void response() {
ExecutorService exec = Executors.newCachedThreadPool();
for (Runnable r : new Runnable[] { new Proxy(), new Prototype() }) {
exec.execute(r);
}
exec.shutdown();
} abstract void preResponse(); class Proxy implements Runnable {
@Override
public void run() {
preResponse();
}
} class Prototype implements Runnable {
@Override
public void run() {
s.response();
}
}
}
ProxyService
编写代理类
package proxy.virtualproxy; public class ProxyServiceImpl extends ProxyService { public ProxyServiceImpl(Service s) {
super(s);
} @Override
void preResponse() {
for (int i = 1; i <= 5; i++) {
try {
Thread.sleep(1900);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("代理进度: " + 20*i + "%");
}
} public static void main(String[] args) {
Service prototype = new ServiceImpl();
Service proxy = new ProxyServiceImpl(prototype);
proxy.response();
}
}
ProxyServiceImpl
输出结果:
服务器正在准备应答...
代理进度: 20%
代理进度: 40%
代理进度: 60%
代理进度: 80%
代理进度: 100%
服务器应答完成!
四、远程代理
暂时没弄明白怎么玩,先留一个坑以后再填吧。
今天是2016年2月3日,明天一早5点的车出发去海南过春节了。祝我的两个朋友:应卓、李浩节日快乐,阖家幸福。
Java设计模式(一)——代理模式的更多相关文章
- Java设计模式之代理模式(静态代理和JDK、CGLib动态代理)以及应用场景
我做了个例子 ,需要可以下载源码:代理模式 1.前言: Spring 的AOP 面向切面编程,是通过动态代理实现的, 由两部分组成:(a) 如果有接口的话 通过 JDK 接口级别的代理 (b) 如果没 ...
- java设计模式6——代理模式
java设计模式6--代理模式 1.代理模式介绍: 1.1.为什么要学习代理模式?因为这就是Spring Aop的底层!(SpringAop 和 SpringMvc) 1.2.代理模式的分类: 静态代 ...
- 夜话JAVA设计模式之代理模式(Proxy)
代理模式定义:为另一个对象提供一个替身或者占位符以控制对这个对象的访问.---<Head First 设计模式> 代理模式换句话说就是给某一个对象创建一个代理对象,由这个代理对象控制对原对 ...
- Java设计模式:代理模式(转)
代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.这里使用到编程中的一 ...
- Java 设计模式_代理模式(2016-08-19)
概念: 代理模式是对象的结构模式.代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用. 就是一个人或者机构代表另一个人或者机构采取行动.在一些情况下,一个客户不想或者不能够直接引用一 ...
- JAVA设计模式:代理模式&& 装饰模式区别
在前面学习了代理模式和装饰模式后,发现对两者之间有时候会混淆,因此对两者进行了区别和理解: 装饰模式你可以这样理解,就像糖一样,卖的时候商家大多要在外面包一层糖纸,其实原本还是糖. public in ...
- Java设计模式:代理模式(二)
承接上文 三.计数代理 计数代理的应用场景是:当客户程序需要在调用服务提供者对象的方法之前或之后执行日志或者计数等额外功能时,就可以用到技术代理模式.计数代理模式并不是把额外操作的代码直接添加到原服务 ...
- java设计模式之代理模式 ,以及和java 回调机制的区别
java 代理模式就是: 将自己要做的事交给别人去做(这个别人就是代理者,自己就是被代理者),为什么自己能做的要交给别人去做了?假如一个小学生小明,现在要写作业,但是又想玩游戏,他更想玩游戏,并且不想 ...
- Java设计模式之代理模式(Proxy)
前言: 最近在研究Retrofit开源框架的时候,其主要核心代码是通过注解标示参数,动态代理模式实现具体接口,反射机制进行参数解析,最终实现发送请求.其实之前在学习Xutils源码的时候,Xutils ...
- Java设计模式 之 代理模式
所谓的代理模式就是为其它类或对象提供一个代理以控制对这个对象的访问.那么常见的代理有远程代理,虚拟代理,保护代理,智能代理. 1. 远程代理:为一个不同地址空间的对象提供一个本地代理对象. 2. 虚拟 ...
随机推荐
- VS2010/VS2013中ashx代码折叠的问题
Tools->Options->TextEditor->File Extension Add ashx Microsoft Visual C# Apply OK 重启VS就可以了,效 ...
- 允许asp.net MVC报 错说明: 访问服务此请求所需的资源时出错。服务器可能未配置为访问所请求的 URL。错误消息 401.2。: 未经授权
运行mvc3程序报以下错误 详细报错如下: “/”应用程序中的服务器错误. 访问被拒绝. 说明: 访问服务此请求所需的资源时出错.服务器可能未配置为访问所请求的 URL. 错误消息 401.2.: 未 ...
- PHP 获取当天 凌晨 时间戳常用代码
echo strtotime(date('Y-m-d')); 获取明天凌晨的时间戳代码:echo strtotime(date('Y-m-d',strtotime('+1 day'))); 附上测试代 ...
- oracle分组取第一条
SELECT * FROM (SELECT ROW_NUMBER() OVER(PARTITION BY x ORDER BY y DESC) rn,test1.* FROM test1) WHERE ...
- 【Demo】QQ,github,微博第三方社交登录
本文主要讲解 集成 第三方社交账号登录 为什么会有这个需求? 主要是因为目前互联网的网站数量太多,如果在各个站点都注册一个账号 用户非常不容易记住每个账号的用户名和密码,并且非常难保证每个账号的密码足 ...
- django 1.7之后python manage.py syncdb没有了
在命令行输入python manage.py createsuperuser按照提示输入即可记得先初始化表. django>1.7 python manage.py makemigrations ...
- iOS学习路线图
一.iOS学习路线图 二.iOS学习路线图--视频篇 阶 段 学完后目标 知识点 配套学习资源(笔记+源码+PPT) 密码 基础阶段 学习周期:24天 学习后目标: ...
- C学习笔记 知识集锦(二)
1. 数组和指针 2. 字符串赋值 3. memset&memcpy 4. 机器数和真值,原码,反码和补码 5. 文件指针和文件描述符 6. 内存泄露和内存损坏 7. 什么是不可移植的程序 ...
- python csv用法
csv打开文件的时候,如下代码,出错: import csv name = "D:\\selenium\\data\\name.csv" inf= csv.reader(open( ...
- ios-将代码创建的视图控件放入拖拽控件的下面
如图所示 图片是拖拽上去的imageView,橘黄色控件是在代码中创建的添加上去的,此时黄色view在imageView 上方 调用方法bringSubviewToFront:试图将imageView ...