`

Design Pattern: Proxy 模式

阅读更多

来看看实现代理的两种方式:Static Proxy与Dynamic Proxy。严格来说这是属于模式的实现方式,不过藉由实例可以更了解Proxy模式的应用。

先来看个例子,这个例子是记录(log)动作,程式中很常需要为某些动作或事件作下记录,以便在事后检视或是作为除错时的资讯,一个最简单的例子如下:

  • HelloSpeaker.java
import java.util.logging.*; 

public class HelloSpeaker { 
    private Logger logger = 
               Logger.getLogger(this.getClass().getName()); 

    public void hello(String name) { 
        logger.log(Level.INFO, "hello method starts....");

        System.out.println("Hello, " + name); 

        logger.log(Level.INFO, "hello method ends...."); 
    } 
} 


HelloSpeaker在执行hello()方法时,您希望能记录该方法已经执行及结束,最简单的作法就是如上在执行的前后加上记录动作,然而 Logger介入了HelloSpeaker中,记录这个动作并不属于HelloSpeaker,这使得HelloSpeaker增加了非业务上需要的逻辑在当中。

想想如果程式中这种记录的动作到处都有需求,上面这种写法势必造成必须复制记录动作的程式码,使得维护记录动作的困难度加大。如果不只有记录动作,有一些非物件本身职责的相关动作也混入了物件之中(例如权限检查、事务管理等等),会使得物件的负担更形加重,甚至混淆了物件的职责,物件本身的职责所占的程式码,或许远小于这些与物件职责不相关动作的程式码。

怎么办,用下面的方法或许好一些,先定义一个介面,然后实作该介面:

  • IHello.java
public interface IHello { 
    public void hello(String name); 
} 

 

  • HelloSpeaker.java
public class HelloSpeaker implements IHello { 
    public void hello(String name) { 
        System.out.println("Hello, " + name); 
    } 
} 


接下来实作一个代理物件HelloProxy:

  • HelloProxy.java
import java.util.logging.*; 

public class HelloProxy implements IHello { 
    private Logger logger = 
              Logger.getLogger(this.getClass().getName()); 
    private IHello helloObject; 

    public HelloProxy(IHello helloObject) { 
        this.helloObject = helloObject; 
    } 

    public void hello(String name) { 
        logger.log(Level.INFO, "hello method starts...."); 

        helloObject.hello(name); 

        logger.log(Level.INFO, "hello method ends...."); 
    } 
}


执行时可以如此:

IHello helloProxy = new HelloProxy(new HelloSpeaker());
helloProxy.hello("Justin");


代理物件HelloProxy将代理真正的HelloSpeaker来执行hello(),并在其前后加上记录的动作,这使得 HelloSpeaker在撰写时不必介入记录动作,HelloSpeaker可以专心于它的职责。

这是Static Proxy的基本范例,然而如您所看到的,代理物件的一个介面只服务于一种类型的物件,而且如果要代理的方法很多,势必要为每个方法进行代理, Static Proxy在程式规模稍大时就必定无法胜任。

Java在JDK 1.3之后加入协助开发Dynamic Proxy功能的类别,我们不必为特定物件与方法撰写特定的代理,使用Dynamic Proxy,可以使得一个handler服务于各个物件,首先,一个handler必须实现 java.lang.reflect.InvocationHandler:

  • LogHandler.java
import java.util.logging.*; 
import java.lang.reflect.*; 

public class LogHandler implements InvocationHandler { 
    private Logger logger = 
               Logger.getLogger(this.getClass().getName()); 
    private Object delegate; 

    public Object bind(Object delegate) { 
        this.delegate = delegate; 
        return Proxy.newProxyInstance(
                 delegate.getClass().getClassLoader(), 
                 delegate.getClass().getInterfaces(), 
                 this); 
    }
 
    public Object invoke(Object proxy, 
                         Method method, 
                         Object[] args) throws Throwable {
        Object result = null; 
        try { 
            logger.log(Level.INFO, 
                         "method starts..." + method); 
            result = method.invoke(delegate, args); 
            logger.log(Level.INFO, 
                         "method ends..." + method); 
        } catch (Exception e){ 
            logger.log(Level.INFO, e.toString()); 
        } 
        return result; 
    } 
} 


InvocationHandler的invoke()方法会传入被代理物件的方法名称与执行参数实际上要执行的方法交由method.invoke (),并在其前后加上记录动作,method.invoke()传回的物件是实际方法执行过后的回传结果。

Dynamic Proxy必须宣告介面,实作该介面,例如:

  • IHello.java
public interface IHello { 
    public void hello(String name); 
} 

 

  • HelloSpeaker.java
public class HelloSpeaker implements IHello { 
    public void hello(String name) { 
        System.out.println("Hello, " + name); 
    } 
} 


java.lang.reflect.Proxy的newProxyInstance()依要代理的物件、介面与handler产生一个代理物件,我们可以使用下面的方法来执行程式:

LogHandler logHandler = new LogHandler();
IHello helloProxy = (IHello) logHandler.bind(
new HelloSpeaker());
helloProxy.hello("Justin");


LogHandler不在服务于特定物件与介面,而HelloSpeaker也不用插入任何有关于记录的动作,它不用意识到记录动作的存在。

上文写的动态代理没有理解真正的代理,特指的是一个抽象类或者接口去实现代理。

 

接口

package com.ijo.proxy;

public interface IHello {
    void sayHello(String name);
}

实现类

package com.ijo.proxy;

public class EnglishSay implements IHello {

 public void sayHello(String name) {
  System.out.println(name + " say hello word!!!");
 }

}
代理类

package com.ijo.proxy.dynamic;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import com.ijo.proxy.EnglishSay;
import com.ijo.proxy.IHello;

public class StudyTest implements InvocationHandler {
 

private IHello delegate;

 

public Object bind(IHello delegate) {
  this.delegate = delegate;
  return Proxy.newProxyInstance(delegate.getClass().getClassLoader(),
    delegate.getClass().getInterfaces(), this);
 }

 

 public Object invoke(Object proxy, Method method, Object[] objs)
   throws Throwable {
  Object result = null;
  System.out.println("this is say begin");
  result = method.invoke(delegate, objs);
  System.out.println("this is say end");
  return result;
 }

 

 public static void main(String[] args) {
  StudyTest studyTest = new StudyTest();
  IHello hello = (IHello) studyTest.bind(new EnglishSay());
  hello.sayHello("chinaxxren ");
 }
}

结果:

this is say begin
chinaxxren  say hello word!!!
this is say end

 

分享到:
评论

相关推荐

    DesignPattern::pencil:设计模式_java实现以及详解

    本资源“DesignPattern::pencil:设计模式_java实现以及详解”提供了一套详细的学习材料,帮助开发者理解和应用设计模式。 该资源的作者是“养码青年-Style”,他通过这个项目记录了自己的设计模式学习过程。鼓励...

    DesignPattern:设计模式

    DesignPattern-master这个压缩包可能包含了一个关于设计模式的项目或者教程资源。 设计模式分为三类:创建型模式(Creational Patterns)、结构型模式(Structural Patterns)和行为型模式(Behavioral Patterns)...

    designPattern:设计模式相关代码实现

    "designPattern:设计模式相关代码实现"这个项目,显然提供了不同设计模式在Java语言中的实际应用示例。 在Java世界里,设计模式主要分为三大类:创建型模式、结构型模式和行为型模式。每种模式都针对特定的编程问题...

    DesignPattern:设计模式.net源代码

    本资源"DesignPattern:设计模式.net源代码"提供了一套基于.NET实现的设计模式示例,旨在帮助程序员更好地理解和应用这些模式。 在"DesignPattern-master"这个压缩包中,你可能找到的文件结构和内容包括: 1. **...

    DesignPattern:设计模式演示程序

    这个名为"DesignPattern"的压缩包文件很可能包含了一个Java实现的各种设计模式的示例程序。 在这个"DesignPattern-master"目录中,我们可以期待找到一系列与设计模式相关的Java源代码文件(.java),每个文件或...

    C++设计模式(Design Pattern)范例源代码

    23种设计模式(Design Pattern)的C++实现范例,包括下面列出的各种模式,代码包含较详细注释。另外附上“设计模式迷你手册.chm”供参考。 注:项目在 VS2008 下使用。 创建型: 抽象工厂模式(Abstract Factory) 生成...

    DesignPattern:C#设计模式示例

    "DesignPattern:C#设计模式示例"这个资源很可能是包含多个C#实现的设计模式示例代码库。 设计模式通常分为三类:创建型、结构型和行为型。每种模式都解决了特定场景下的问题,并提供了良好的代码组织和扩展性。 ...

    设计模式源码Head_First_DesignPattern_src

    在本文中,我们将深入探讨设计模式的核心概念,并结合"Head First DesignPattern_src"中的源码,详细解析一些关键的设计模式。 1. 单例模式(Singleton): 单例模式确保一个类只有一个实例,并提供全局访问点。在...

    FOAD-DesignPattern:FOAD-DesignPattern

    5. 代理模式(Proxy Pattern): 代理模式为其他对象提供一种代理以控制对这个对象的访问。在C#中,可以使用接口或者继承来实现静态代理,或者使用.NET Framework的`System.Reflection.Emit`命名空间动态生成代理类...

    designPattern:练习设计模式

    本项目"designPattern:练习设计模式"提供了一个学习和实践各种设计模式的平台。 1. **单例模式**:确保一个类只有一个实例,并提供一个全局访问点。在Java中,单例模式通常通过双重检查锁定、静态内部类或枚举来...

    DesignPattern:设计模式的学习笔记和示例代码

    设计模式是软件工程中的一种最佳实践,它是在特定情境下解决常见问题的经验总结。...在DesignPattern-master这个压缩包中,你可以找到关于这些模式的详细讲解和实例代码,为你的Java开发之旅提供宝贵的参考资料。

    DesignPattern:有关设计模式的一些演示

    这个名为"DesignPattern:有关设计模式的一些演示"的项目,可能是为了帮助开发者理解和应用各种设计模式。 设计模式分为三大类:创建型、结构型和行为型。创建型模式关注对象的创建过程,如单例(Singleton)、工厂...

    Design*Pattern*Framework*4.5

    "Design*Pattern*Framework*4.5" 可能指的是一个基于 .NET Framework 4.5 的设计模式实现或教程集合。 设计模式是经验丰富的软件开发者的智慧结晶,它们被分为三类:创建型、结构型和行为型。创建型模式涉及对象的...

    designpattern:Head First 设计模式练习

    代理模式(Proxy)为其他对象提供一种代理以控制对这个对象的访问。在Java中,静态代理和动态代理(JDK Proxy和CGLIB)是常见的实现方式。 最后,还有建造者模式(Builder)用于分步骤构建复杂对象,隔离对象的构造...

    Design-pattern:设计模式

    这个名为"Design-pattern:设计模式"的压缩包可能包含了一个关于设计模式的学习资源,比如代码示例或者教程。 创建型设计模式是设计模式中的一个类别,主要关注对象的创建过程。这类模式包括工厂方法(Factory ...

    DesignPattern:关于设计模式

    在这个“DesignPattern”仓库中,可能包含了对各种设计模式的详细解释、示例和应用。 设计模式分为三大类:创建型、结构型和行为型模式。创建型模式主要关注对象的创建过程,如单例模式(Singleton)、工厂模式...

    JAVA 23种设计模式(全).Design Pattern_Java模式

    本资料包“JAVA 23种设计模式(全).Design Pattern_Java模式”涵盖了所有23种经典的GOF(GoF,Gang of Four)设计模式,旨在帮助开发者深入理解和应用这些模式。 首先,我们来看一下23种设计模式的分类: 1. **创建...

    designpattern:PHP设计模式教程

    本教程的"designpattern-master"可能包含以上各种设计模式的实例代码和详细解释,帮助学习者通过实践掌握这些模式。在实际项目中,灵活运用这些设计模式可以提高代码质量,使项目更加健壮和易于维护。对于PHP开发者...

    DesignPattern:来自 http 的设计模式参考

    在"DesignPattern-master"这个压缩包中,可能包含了这些模式的Java实现示例,以及相关的解释和用法说明。通过学习和应用这些模式,开发者可以提高代码质量,降低维护成本,并提升软件系统的可扩展性。对于任何Java...

Global site tag (gtag.js) - Google Analytics