设计模式_JAVA动态代理设计模式

 一、  什么是代理设计模式

为其他对象提供一种代理以控制对这个对象的访问。

二、  静态代理设计模式

在以后的日子里,我会用学习剩下的时间和大家一起学习Java设计模式,书写有误之处,还望指正!谢谢!

我们的模式之旅,从这里开始

(注意:模式讲解过程会涉及到spring,struts,hibernate,jsf的一些东西,因为我相信这样做是有益的呵呵)

代码一

日志实现的一般方法:


import java.util.logging.*;

public class HelpSpeaker {

    public static void main(String[] name) {
        
        HelpSpeaker help=new HelpSpeaker();
        
        Logger logger=
            Logger.getLogger(help.getClass().getName());
        
        //方法执行开始时留下记录
        logger.log(Level.INFO,"hello method starts  ");
        
        //程序的主要功能
        System.out.println("Hello");
        
        
        //方法执行完毕前留下记录
        logger.log(Level.INFO,"hello method ends  ");

    }
}


这样写的好处是简单,当我们的代码量不多的时候,呵呵这样写无疑是首选。

     
这样写,我们必须在每个代码里都写上这些内容,当我们的代码量多起来的时候,比如,100个代码里面需要记录日志,想想需要多大的工作量,再想想,但我们在想在日志里添加一些内容的时候,或者需要去掉或分类管理的话,那有多乱,这样重复而无聊的工作,是多么另人望而生畏!!!



代码二

由于这种做法的局限性不合理性于是出现了代理;下面我介绍下我代码中的角色和对象:

/*
*
电脑批发商
**/

public interface Computer {
    public void buy(String name);
}

 

/*
*
联想电脑公司
**/

public class Lianxiang implements Computer
{

    public void buy(String name) 
    {
      System.out.println(name+"  联想电脑公司产品!");
    }

}

 

 1/*
 2*三星电脑公司
 3**/
 4public class Sanxing implements Computer {
 5
 6    public void buy(String name) {
 7       
 8       System.out.println(name+"  三星电脑公司产品!");
 9    }
10
11}

 

/*
*
电脑销售代理商
**/

import java.util.logging.Level;
import java.util.logging.Logger;

public class ComputerProxy implements Computer {

    private Logger logger=
            Logger.getLogger(this.getClass().getName());
    
    private Computer computer;
    
    public  ComputerProxy(Computer helpObject){
        this.computer=helpObject;
    }
    
    public void buy(String name) {
           
        //方法执行开始时留下记录
        logger.log(Level.INFO,"hello method starts  ");
        
        //程序的主要功能
        computer.buy(name);
        
        
        //方法执行完毕前留下记录
        logger.log(Level.INFO,"hello method ends  ");
    }
    
    private void log(String msg){
        logger.log(Level.INFO,msg);
    }

 

/*
*
买电脑的客户有两个
**/

public class BuyComputer {

    public static void main(String[] args) {

        ComputerProxy proxy = new ComputerProxy(new Lianxiang());

        proxy.buy("我想买一台联想电脑");
        
        ComputerProxy proxy1 = new ComputerProxy(new Sanxing());

        proxy1.buy("我想买一台三星电脑");

    }

}


执行结果:

我想买一台联想电脑  联想电脑公司产品!
我想买一台三星电脑  三星电脑公司产品!
2007-8-8 21:01:27 com.lusm.spring.ComputerProxy buy
信息: hello method starts  
2007-8-8 21:01:28 com.lusm.spring.ComputerProxy buy
信息: hello method ends  
2007-8-8 21:01:28 com.lusm.spring.ComputerProxy buy
信息: hello method starts  
2007-8-8 21:01:28 com.lusm.spring.ComputerProxy buy
信息: hello method ends  


很明显,我们在main里的代码非常之少,而且可以通过(一个或者多个)批发商改变很多,代理内容,比如,批发商可以加一些附加的服务(送网线,送鼠标....),代码之间通过接口减低了程序块间的偶合性;下面让我们分析一下,代码是怎么工作的?



代码分析:

仔细看完代码我们知道客户买电脑是怎么一个过程:

    
用户找到代理商buy一台自己想要买的电脑,通过这两个语句,代理商知道用户想要买什么牌子的电脑

//想买联想电脑
ComputerProxy proxy = new ComputerProxy(new Lianxiang());

//想买三星电脑
ComputerProxy proxy1 = new ComputerProxy(new Sanxing());


   
然后代理商根据用户的需要,找到电脑批发商Computer(注意:由于代理商和批发商之间并没有继承关系extends,只是充当一个批发代理的角色implements,提醒一句,在Java里面,我们完全可以把接口看成角色,把类看成角色的表现实体--对象

private Computer computer;


问批发商说:里面这里有没有两种电脑,一种叫联想的电脑,一种叫三星电脑

public  ComputerProxy(Computer helpObject){
        this.computer=helpObject;
    }


批发商看了看自己手上的货单说:有啊!我找两台给你!

public void buy(String name) {
           
        //方法执行开始时留下记录
        logger.log(Level.INFO,"hello method starts  ");
        
        //程序的主要功能
        computer.buy(name);
        
        
        //方法执行完毕前留下记录
        logger.log(Level.INFO,"hello method ends  ");
    }
private void log(String msg){
        logger.log(Level.INFO,msg);
    }


我看到,代理商业是个在经营方面,非常用心的人,在工作的时候总是带一个笔记

private Logger logger=Logger.getLogger(this.getClass().getName());


在买的时候就用log方法把整个买个过成记录下来。
 


呵呵!大家,我的故事讲完了!希望大家用心体会,有什么问题请留言!谢谢您的支持!!!

 

三、  动态代理设计模式

前面一个文章里的代码很简单(只是让大家了解什么是代理),实现的是静态代理,做为电脑代理商的ComputerProxy,在电脑行业为电脑生产商(三星,联想)和客户提供服务,提供各种方便。
       
郁闷的是,如果我现在增加一个行业,比如下面要讲到的Car汽车行业,那么,我们只能增加一个代理了,也就是说我们要再写一个CarProxy代码,我们现在假设我们有很多个行业,那么,无疑我们的工作量开始大了,有没有什么办法让我们的代理商实现跨行业代理呢?
       
答案是:可以。这就是我们这里讲的动态代理产生存在的意义了。

请看代码

在原有代码的基础上我们做了这些宽展:

/*
*
汽车批发商
*
这样我们的代码中就有了电脑和汽车这两个批发商
*/

public interface Car {
    public void buyCar(String name);
}

 

/*
*
劳斯莱斯汽车公司
*/

public class RollsRoyce implements Car {

    public void buyCar(String name) {
        
        System.out.println(name+"  劳斯莱斯公司产品!");
    }

}

 

/*
*
所有行业代理商
*
有了它我们的客户可以通过他买个各种产品
*/

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.logging.Level;
import java.util.logging.Logger;

public class AllthingsProxy implements InvocationHandler {

    private Logger logger=
        Logger.getLogger(this.getClass().getName());
    
    private Object allthings;
    
    //实现对象绑定
    public Object bind(Object allthings){
        
        this.allthings = allthings;
        
        //这里传入newProxyInstance的参数分别是 目标object
        //
Lianxiang,Sanxing,interface(Computer),AllthingsProxy
        return Proxy.newProxyInstance(allthings.getClass().getClassLoader(),
                                    allthings.getClass().getInterfaces(), this);
    }
    
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        
        Object result = null;
        
        try{
        log("method starts " + method);
        
        result=method.invoke(allthings, args);

        logger.log(Level.INFO , "method ends " + method);
        
        }catch(Exception e){
            log(e.toString());
        }
        
        return result;
    }
    
    private void log(String msg){
        logger.log(Level.INFO,msg);
    }

}



在测试类BuyAllThings中,我们通过bing方法绑定对象(所要买的东西),让代理商了解到,客户想买什么?
(这里重在了解模式,具体方法的实现如不了解请自行查询API文档)


/*
*
三个客户两个买电脑一个买汽车
*
他们找到同个代理商
*/

public class BuyAllThing {

    public static void main(String[] args) {
        
        AllthingsProxy allthingsproxy = new AllthingsProxy();
        
        Computer SanxingProxy=(Computer)allthingsproxy.bind(new Sanxing());
        
        SanxingProxy.buyComputer("我想买一台三星电脑");
        
        Computer lianxiangProxy=(Computer)allthingsproxy.bind(new Lianxiang());
        
        lianxiangProxy.buyComputer("我想买一台联想电脑");
        
        Car rRollsRoyceProxy=(Car)allthingsproxy.bind(new RollsRoyce());
        
        RollsRoyceProxy.buyCar("我想买一辆劳斯莱斯汽车");

    }

}


执行结果

我想买一台三星电脑  三星电脑公司产品!
我想买一台联想电脑  联想电脑公司产品!
我想买一辆劳斯莱斯汽车  劳斯莱斯公司产品!
2007-8-9 13:08:41 com.lusm.spring.AllthingsProxy log
信息: method starts public abstract void com.lusm.spring.Computer.buyComputer(java.lang.String)
2007-8-9 13:08:42 com.lusm.spring.AllthingsProxy invoke
信息: method ends public abstract void com.lusm.spring.Computer.buyComputer(java.lang.String)
2007-8-9 13:08:42 com.lusm.spring.AllthingsProxy log
信息: method starts public abstract void com.lusm.spring.Computer.buyComputer(java.lang.String)
2007-8-9 13:08:42 com.lusm.spring.AllthingsProxy invoke
信息: method ends public abstract void com.lusm.spring.Computer.buyComputer(java.lang.String)
2007-8-9 13:08:42 com.lusm.spring.AllthingsProxy log
信息: method starts public abstract void com.lusm.spring.Car.buyCar(java.lang.String)
2007-8-9 13:08:42 com.lusm.spring.AllthingsProxy invoke
信息: method ends public abstract void com.lusm.spring.Car.buyCar(java.lang.String)


我们可以任意的增加代理商的业务,比如,叫他代理电器,食物......,我们看到我们不需要更改原有的代码。这是动态代理带来的好处!

那我们的AllthingsProxy是怎么作到动态代理的呢?

AllthingsProxy
宽展了InvocationHandler并实现了里面的代理方法,返回一个Object对象,

    public Object invoke(Object proxy, Method method, Object[] args)
    throws Throwable;


来实现对汽车,电脑这些批发商的动态代理(代理商同过它代理所有行业)。

AllthingsProxy
中的bind实现了客户和代理商间的通信(通过它代理商知道客户想要买什么)

这和我们 BuyAllThing测试类main

代理对象=(绑定对象)allthingsproxy.bind(绑定对象(客户想买的东西))


想对应。

        
呵呵,讲完了!也许有的朋友看不懂这里在说什么?不必着急,学习都需要过程,等你的学习到某个阶段的时候,回头想想,也许认识就会加深许多,本人觉得Java是比较高级的语言,自身的发展也只直遵循着软件设计优化(代码重用)方向发展,重视设计思想,而不是去改变语言的语法或接口api,这是许多语言所缺乏的,如一个在VC6中编写的代码,拿到Visual Studio2005Visual Studio2008去运行很容易出现问题。

      
也许你并不清楚我在说什么?但是这一切会在你的Spring学习中渐渐清楚起来!

      
以后的代码可能需要必要的IDE才能使用,本人使用的是:
       MyEclipse6.0M1+Eclipse3.3 

       数据库用的是:
      Oralce10g
或者Mysql6.0

 

 

 

 

 

 

 

你可能感兴趣的:(设计模式)