设计模式四—"代理模式"(静态代理)
代理模式的一个核心思想就是通过实现延迟加载,提升系统启动速度,提升用户体验。当然代理模式还有其他的优势,比如安全考虑,或者远程调用等等。同时,Java的动态代理技术也具有很高的灵活性。
从静态代理开始
先从一个实际情况下可能碰到的例子来说明代理模式。
代理模式主要有三个主要组成:
(1)代理类与真实主题公共提供对外的主题接口
(2)代理类,用来代理或封装真实主题
(3)真实主题,封装真正的业务逻辑
Example:
(1)主题接口,定义一个DBQuery接口
1 package com.sample; 2 3 public interface IDBQuery { 4 public String query(); 5 public void insert(); 6 public void update(); 7 public void delete(); 8 }
(2)真实主题类,实现真正request业务逻辑测试代码中用一个Tread.sleap()来模拟这类真实封装了业务逻辑的类的实例化操作。
1 package com.sample; 2 3 public class DBQuery implements IDBQuery { 4 public DBQuery(){ 5 try{ 6 Thread.sleep(10000);//simulate ops creating connections between 7 } 8 catch(Exception ie){ 9 ie.printStackTrace(); 10 } 11 } 12 13 public String query() { 14 return "request str"; 15 } 16 public void update() { 17 System.out.println("update a record"); 18 } 19 20 public void insert() { 21 System.out.println("insert a record"); 22 } 23 24 public void delete() { 25 System.out.println("delete a record"); 26 } 27 }
(3)代理类,实现延迟加载,轻量级对象,创建非常快
1 package com.sample; 2 3 public class DBQueryProxy implements IDBQuery{ 4 private IDBQuery instance = null; 5 6 public DBQueryProxy(){ 7 } 8 public DBQueryProxy(IDBQuery iDBQuery){ 9 this.instance = iDBQuery; 10 } 11 public String query() { 12 lazyInit(); 13 return instance.query(); 14 } 15 16 public void insert() { 17 lazyInit(); 18 instance.insert(); 19 } 20 21 public void update() { 22 lazyInit(); 23 instance.update(); 24 } 25 26 public void delete() { 27 lazyInit(); 28 instance.delete(); 29 } 30 31 public void lazyInit(){ 32 if(instance == null) 33 instance = new DBQuery(); 34 } 35 }
测试使用代理类
1 package com.sample; 2 3 public class Test { 4 public static void main(String[] args) { 5 IDBQuery dbQueryProxy = new DBQueryProxy(); 6 long begTime = System.currentTimeMillis(); 7 System.out.println(dbQueryProxy.query()); 8 long endTime = System.currentTimeMillis(); 9 System.out.println("Proxy init real Subject cost:" + (endTime-begTime)); 10 dbQueryProxy.update(); 11 dbQueryProxy.insert(); 12 dbQueryProxy.delete(); 13 } 14 }
只用当dbQuery调用query的时候,封装了业务逻辑的类才会被实例化。使用代理模式的目的在于加速系统启动时间,有点类似于hibernate的lazy init。
同时使用代理类,隐藏了真实主题内的业务逻辑,在安全性方面的优势也就体现了出来。
来段总结吧:我们可以这样理解代理模式带来的性能优势,用户需要请求一个db的connection,而创建connection是一个非常耗时的操作,如果请求了,就去实例化对象,执行业务逻辑,如果没有请求的话,不会实例化对象,这样在服务端的性能优势就体现出来了。
但是静态代理也有缺点,假设主题接口中提供较多的方法,为每一个接口都去写一个代理方法非常麻烦,如果接口产生变化,封装了业务逻辑的真实主题类,和代理类中的代理方法的实现代码就需要大量的修改工作。java中的动态代理技术就能很好的处理这个问题。使用动态代理技术,不需要再为真是主题写一个形式上完全一样的代理类,同时,我们可以在程序中动态指定代理类的执行逻辑,灵活性非常大~