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

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

一、静态代理

设计测试接口,提供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. 关于type erasure

    哇,好久没有写blog了,再不写的话,blog的秘密都要忘记了,嘿嘿. 最近在试着参与一个开源项目,名字叫avim(A Vibrate IM),别想多了哟.地址是:https://github.com ...

  2. logoff remote desktop sessions via command line tools

    This trick I learned from my one of ex-college.  In Windows servers, only two remote desktop session ...

  3. 细说SaaS BI国际市场众生相,你准备好了么?

    SaaS商业智能(BI)历程 在笔者看来,SaaS BI(也有称SaaS 商业智能.云BI)算是一个慢热的概念.远在十几前年便已经提出并有公司践行.而随着SaaS服务从早期的CRM.ERP.HR等领域 ...

  4. MYSQL 多行转多列

    mysql 行变列(多行变成一行/多行合并成一行/多行合并成多列/合并行),我觉得这都是一个意思 数据库结构如图: 而我想让同一个人的不同成绩变成此人在这一行不同列上显示出来,此时分为2中展现: 第一 ...

  5. 关于CAShapeLayer的一些实用案例和技巧【转】

    本文授权转载,作者:@景铭巴巴 一.使用CAShapeLayer实现复杂的View的遮罩效果 1.1.案例演示 最近在整理一个聊天的项目的时候,发送图片的时候,会有一个三角的指向效果,指向这张图片的发 ...

  6. C# EF增删改查

    1.增 //1.创建一个EF数据上下文对象 MyDBEntities context=new MyDBEntities(); //2.将要添加的数据,封装成对象 Users user = new Us ...

  7. 分布式缓存Memcached---开篇的话

    大数据.高并发这是最近一段时间内被IT行业提的最为火热的概念,看过<大数据时代>的同学应该不会陌生大数据的概念,尤其是对于互联网行业来说,大数据是每天都要接触的问题,简单通俗地说,每天得大 ...

  8. 使用CTE减少统计子查询

    Set Statistics IO ON SET STATISTICS TIME ON --/*--原来语句 DECLARE @CkNo nvarchar(4000),@ProWarn int,@Sk ...

  9. Python之路----------shutil模块

    高级的文件.文件夹.压缩包 处理模块 复制文件: import shutil f1 = open('test') f2 = open('test2','w') shutil.copyfileobj(f ...

  10. LL谱面分析和难度标定

    LL谱面分析和难度标定 先介绍一下LL谱面的存储方式:TimeLine序列(简称TL序列),TL序列中的每一个元素(即音符)可以由一个C语言中的结构体来表示: struct note{ int lin ...