有高手云:了解设计模式才算是入门级的程序员。

所以为了入门我打算把我学习到的设计模式逐条总结下来。和别人的文章不同,我几乎只提供了测试源码与细节分类。原因是,我相信对于设计来说,你永远无法给出终极答案。不同的人看到会有不同的理解,所以大家一起讨论吧。

一、静态代理

设计测试接口,提供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设计模式(一)——代理模式的更多相关文章

  1. Java设计模式之代理模式(静态代理和JDK、CGLib动态代理)以及应用场景

    我做了个例子 ,需要可以下载源码:代理模式 1.前言: Spring 的AOP 面向切面编程,是通过动态代理实现的, 由两部分组成:(a) 如果有接口的话 通过 JDK 接口级别的代理 (b) 如果没 ...

  2. java设计模式6——代理模式

    java设计模式6--代理模式 1.代理模式介绍: 1.1.为什么要学习代理模式?因为这就是Spring Aop的底层!(SpringAop 和 SpringMvc) 1.2.代理模式的分类: 静态代 ...

  3. 夜话JAVA设计模式之代理模式(Proxy)

    代理模式定义:为另一个对象提供一个替身或者占位符以控制对这个对象的访问.---<Head First 设计模式> 代理模式换句话说就是给某一个对象创建一个代理对象,由这个代理对象控制对原对 ...

  4. Java设计模式:代理模式(转)

    代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.这里使用到编程中的一 ...

  5. Java 设计模式_代理模式(2016-08-19)

    概念: 代理模式是对象的结构模式.代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用. 就是一个人或者机构代表另一个人或者机构采取行动.在一些情况下,一个客户不想或者不能够直接引用一 ...

  6. JAVA设计模式:代理模式&& 装饰模式区别

    在前面学习了代理模式和装饰模式后,发现对两者之间有时候会混淆,因此对两者进行了区别和理解: 装饰模式你可以这样理解,就像糖一样,卖的时候商家大多要在外面包一层糖纸,其实原本还是糖. public in ...

  7. Java设计模式:代理模式(二)

    承接上文 三.计数代理 计数代理的应用场景是:当客户程序需要在调用服务提供者对象的方法之前或之后执行日志或者计数等额外功能时,就可以用到技术代理模式.计数代理模式并不是把额外操作的代码直接添加到原服务 ...

  8. java设计模式之代理模式 ,以及和java 回调机制的区别

    java 代理模式就是: 将自己要做的事交给别人去做(这个别人就是代理者,自己就是被代理者),为什么自己能做的要交给别人去做了?假如一个小学生小明,现在要写作业,但是又想玩游戏,他更想玩游戏,并且不想 ...

  9. Java设计模式之代理模式(Proxy)

    前言: 最近在研究Retrofit开源框架的时候,其主要核心代码是通过注解标示参数,动态代理模式实现具体接口,反射机制进行参数解析,最终实现发送请求.其实之前在学习Xutils源码的时候,Xutils ...

  10. Java设计模式 之 代理模式

    所谓的代理模式就是为其它类或对象提供一个代理以控制对这个对象的访问.那么常见的代理有远程代理,虚拟代理,保护代理,智能代理. 1. 远程代理:为一个不同地址空间的对象提供一个本地代理对象. 2. 虚拟 ...

随机推荐

  1. 外部函数test显示的返回内部函数add的调用

    前段时间有个需求中有点击datagrid的单元格实现某种事件,皇冠现金代理调用datagrid的onclickCell这个方法很容易实现,但是体验不好啊,完全不知道自己刚才点击的是哪个单元格,然后就尝 ...

  2. python-高阶函数

    map函数 map(func, Iterable) , 返回一个Iterable的map对象 reduce函数 reduce(func,Iterable), 将后面可迭代对象的每个元素都作用于函数(函 ...

  3. 两个NOI题目的启迪8皇后和算24

    论出于什么原因和目的,学习C++已经有一个星期左右,从开始就在做NOI的题目,到现在也没有正式的看<Primer C++>,不过还是受益良多,毕竟C++是一种”低级的高级语言“,而且NOI ...

  4. cloudera learning3:Hadoop配置和守护进程logs

    Services:Haddoop cluster上可以部署的组件,比如HDFS,YARN,HBase等. Roles:在service配置时,由Cloudera Manager创建.比如NameNod ...

  5. MVC 关于easyui-datebox 赋值问题

    view <script type="text/javascript"> $(function () { var date = '@ViewData["end ...

  6. mac eclipse 添加pydev插件 步骤

    前提:eclipse环境可以正常使用  python环境可以正常使用 1.下载pydev(http://www.pydev.org/)

  7. 网络监测工具-iftop教程

    在类Unix系统中可以使用top查看系统资源.进程.内存占用等信息.查看网络状态可以使用netstat.nmap等工具.若要查看实时的网络流量,监控TCP/IP连接等,则可以使用iftop. 一.if ...

  8. linux系统中如何查看日志(转)

    cat tail -f 日 志 文 件 说    明 /var/log/message 系统启动后的信息和错误日志,是Red Hat Linux中最常用的日志之一 /var/log/secure 与安 ...

  9. VC6.0中友元函数无法访问类私有成员的解决办法

    举个例子: 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 #inclu ...

  10. Leetcode: Unique Substrings in Wraparound String

    Consider the string s to be the infinite wraparound string of "abcdefghijklmnopqrstuvwxyz" ...