【设计模式】Proxy 代理模式

【设计模式】Proxy 代理模式

1.代理模式的定义

代理模式:为另一个对象提供一个替身或占位符以控制对这个对象的访问。

2.静态代理

首先我们通过案例来引出为什么我们需要使用代理模式。

我们给出如下一个接口Moveable 和该接口的实现类:

Moveable.java

package com.proxy;
public interface Moveable {
    void move();
}

Tank.java

package com.proxy;

import java.util.Random;
public class Tank implements Moveable{
    @Override
    public void move() {
        //long start = System.currentTimeMillis();
        //System.out.println("Tank Moving...");</span>
        try {
            Thread.sleep(new Random().nextInt(10000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //long end = System.currentTimeMillis();
        //System.out.println("time:"+(end-start));</span>
    }
}

需求:我们想要知道实现Moveable的实现类,move()方法的运行时间

解决:我们可以通过在Tank.java的源码中插入自己的代码(红色部分),来统计这个move()方法的运行时间。

问题:如果我们不能对源码进行修改,或者你没有源码,比如这个方法是别人提供的包中提供的class文件。

现实意义是我们对java进行性能测试,我们就需要对各个方法前后记录时间,打印日志等。

方法1:使用继承重写方法,把原来的方法前后添加一些逻辑。

对Tank2调用move()方法,它永远调用的是父类的方法,从这个角度上来说它是父类的一个代理。

Tank2.java

package com.proxy;
/**
 * 通过继承的方式来实现记录方法move()的运行时间
 */
public class Tank2 extends Tank {
    public void move(){
        long start = System.currentTimeMillis();
        super.move();
        long end = System.currentTimeMillis();
        System.out.println("time:"+(end-start));
    }
}

Client.java 测试类

方法2:使用聚合的方式

Tank3在调用move方法的时候永远调用的是实现Moveable接口的实现类的move()方法。

在这种情况下Tank3相当于Moveable实现类的一个代理,将具体的实现替换成特定类。

Tank3.java

package com.proxy;
import com.proxy.Moveable;
public class TankTimeProxy implements Moveable {
    Moveable t;
    public TankTimeProxy(Moveable t) {
        this.t = t;
    }
    public void move() {
        long start = System.currentTimeMillis();
        System.out.println("startTime:" + start);</span>
        this.t.move();
        long end = System.currentTimeMillis();
        System.out.println("time:" + (end - start));</span>
    }
}

以上两种方式聚合要好与继承的方式,

原因:当我们需要添加的事物变得比较多时(比如在方法开始结束时不仅还要记录时间,检查权限,日志等),

继承会比较多,而聚合就可以很好的处理各个功能上的叠加的情况。

假设:我们需要在调用move()方法前先记录日志,在记录时间

TankLogProxy.java

package com.proxy;
public class TankLogProxy implements Moveable{
    Moveable t;
    public TankLogProxy(Moveable t){
        super();
        this.t = t;
    }
    @Override
    public void move() {
        System.out.println("Tank Start ....");</span>
        t.move();
        System.out.println("Tank Stop ....");</span>
    }

TankTimeProxy.java

package com.proxy;
public class TankTimeProxy implements Moveable {
    Moveable t;
    public TankTimeProxy(Moveable t){
        super();
        this.t = t;
    }
    @Override
    public void move() {
        long start = System.currentTimeMillis();
        System.out.println("startTime:"+start);</span>
        t.move();
        long end = System.currentTimeMillis();
        System.out.println("time:"+(end-start));</span>
    }
}

测试类Client.java

package com.proxy;
public class Client {
    public static void main (String [] args){
         //先记录日志,再记录时间
         Tank t = new Tank();
         TankTimeProxy ttp = new TankTimeProxy(t);
         TankLogProxy tlp = new TankLogProxy(ttp);
         Moveable m = tlp;
         m.move();

         /**先记录时间,再记录日志*/
        /**
         Tank t = new Tank();
         TankLogProxy tlp = new TankLogProxy(t);
         TankTimeProxy ttp = new TankTimeProxy(tlp);
         Moveable m = ttp;
         m.move();
         */
    }
}

运行结果:

Tank Start ....
startTime:1465278163874
Tank Moving...
time:4330
Tank Stop ....

以上就是静态代理的典型例子。但是问题来了,我们能不能动态生成一个代理,能够做为任何目标的代理(前提是代理的类和被代理的类都实现了共同的接口)。

3.代理模式类图

4.动态代理的引入

动态代理的目标:解决类太多的问题,为了可以对任意的对象、任意的接口方法,实现任意的代理。

静态代理:我们的代理类是需要具体写出来的。

动态代理:不关心生成代理类的名称。用户需要的代理对象由Proxy代理类直接产生。

问题:那么这个代理类Proxy如何产生代理对象。

1.假设我们能够将一段源码的字符串进行编译(动态编译),产生一个新的类(我们实现逻辑的代理类)。

对于以上的例子我们可以这样描述:我们在源文件中删除TankTimeProxy.java文件,把TankTimeProxy.java源码作为字符串,

进行动态编译,就相当于产生了TankTimeProxy对象,这段代码我们想完成什么逻辑,就完成我们自己的业务逻辑。

问题来了:我们如何动态编译这段代码

解决:Jdk6 Complier API, CGLib, ASM

2.把这个新的类Load到内存,再由这个新的类产生新的对象(代理类生成的对象)。

例子:

下面我们来模拟下动态代理的过程(实际上字符串源码部分我们也是可以动态生成的,

为了简单起见,我们先把字符串源码写死)

package com.proxy.test;
import com.proxy.Moveable;
import com.proxy.Tank;
import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.net.URL;
import java.net.URLClassLoader;
public class Test1 {
    public static void main(String[] args) throws Exception {
        String rt = "\r\n";
        String src = "package com.proxy;" + rt +
                "  public class TankTimeProxy implements Moveable {" + rt +
                "       Moveable t;" + rt +
                "  public TankTimeProxy(Moveable t){" + rt +
                "      super();" + rt +
                "      this.t = t;" + rt +
                "     }" + rt +
                "  @Override" + rt +
                "  public void move() {" + rt +
                "     long start = System.currentTimeMillis();" + rt +
                "     System.out.println(\"startTime:\"+start);" + rt +
                "     t.move();" + rt +
                "     long end = System.currentTimeMillis();" + rt +
                "     System.out.println(\"time:\"+(end-start));" + rt +
                "  }" + rt +
                " }";
        //我们想让这段代码编译,如何做呢?
        //1.首先,我们可以把这段代码写到临时文件中
        String fileName = System.getProperty("user.dir") +
                "/src/com/proxy/TankTimeProxy.java";
        File f = new File(fileName);
        FileWriter fw = new FileWriter(f);
        fw.write(src);
        fw.flush();
        fw.close();
        //2.编译生成的Java文件生成class文件
        //获取此平台提供的 Java? 编程语言编译器
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager fileMagr = compiler.getStandardFileManager(null, null, null);
        Iterable units = fileMagr.getJavaFileObjects(fileName);
        JavaCompiler.CompilationTask t = compiler.getTask(null, fileMagr, null, null, null, units);
        t.call();
        fileMagr.close();

        //3.将编译生成的class的load 到内存,生成新对象
        //注意:使用ClassLoader()必须保证那个class在classPath路径下,
        //所以我们使用URLClassLoader
        URL[] urls = new URL[]{new URL("file:/" + System.getProperty("user.dir") + "/src")};
        URLClassLoader ul = new URLClassLoader(urls);
        Class c = ul.loadClass("com.proxy.TankTimeProxy");
        System.out.println(c);

        //4.生成代理类对象
        Constructor ctr = c.getConstructor(Moveable.class);
        Moveable m = (Moveable)ctr.newInstance(new Tank());
        m.move();
    }
}

运行结果:

class com.proxy.TankTimeProxy
startTime:1465283901100
Tank Moving...
time:1043

问题1:现在我们可以实现指定接口(Moveable)的动态代理,但是我们要产生实现任何接口的代理,应该怎么做?

解决:我们把接口也作为参数传进去。

问题2:对于接口的方法是不可以写死的,我们要能够使用户动态指定对接口方法的处理方式

解决:定义处理逻辑的接口InvocationHandler,对方法的处理放在实现中,由具体的子类实现代理逻辑,

封装InvocationHandler中。

下面我们来模拟JDK动态代理的实现来进行讲解。

1.定义InvocationHandler接口,我们将代理对象的方法处理逻辑放在InvocationHandler实现的子类中。

处理的具体方式是由其子类来决定的。

InvocationHandler.java

package com.proxy;
import java.lang.reflect.Method;
//为方法处理逻辑定义一个统一的接口
public interface InvocationHandler {

    public void invoke(Object o, Method m);

 }

2.通过调用Proxy.newProxyInstance(Class infce,  InvocationHandler h)来产生代理类的代理对象。

问题的关键:我们如何动态产生代理对象呢?

解决:这个方法有两个参数,

Class infce:为了对不同的接口进行代理,我们把接口作为参数传递进去。

InvocationHandler h:对方法的逻辑的处理,我们通过InvocationHandler 具体子类来实现,并做为入参传递给代理类。

这样一来我们就可以对任意的对象(target)、任意的接口方法(infce)、实现任意的代理(InvocationHandler)。

Proxy.java

package com.proxy;
import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
public class Proxy {
    public static Object newProxyInstance(Class infce, InvocationHandler h) throws Exception {
        String rt = "\r\n";
        String methodStr = "";
        Method[] methods = infce.getMethods();
        /**写一个循环,将所用的方法都拿出来*/
        for(Method m : methods) {
            methodStr += "@Override" + rt +
                    "public void " + m.getName() + "() {" + rt +
                    "    try {" + rt +
                    "    Method md = " + infce.getName() + ".class.getMethod(\"" + m.getName() + "\");" + rt +
                    "    h.invoke(this, md);" + rt +
                    "    }catch(Exception e) {e.printStackTrace();}" + rt +
                    "}";
        }
        String src = "package com.proxy;" + rt +
                "import java.lang.reflect.Method;" + rt +
                "  public class $Proxy1 implements "+infce.getName()+" {" + rt +
                "  com.proxy.InvocationHandler h;" + rt +
                "  public $Proxy1(InvocationHandler h){" + rt +
                "      this.h = h;" + rt +
                "     }" + rt +
                      methodStr +
                " }";

        //1.首先,我们可以把这段代码写到临时文件中
        String fileName = System.getProperty("user.dir") +
                "/src/com/proxy/$Proxy1.java";
        File f = new File(fileName);
        FileWriter fw = new FileWriter(f);
        fw.write(src);
        fw.flush();
        fw.close();

        //2.编译生成的Java文件生成class文件
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager fileMagr = compiler.getStandardFileManager(null, null, null);
        Iterable units = fileMagr.getJavaFileObjects(fileName);
        JavaCompiler.CompilationTask t = compiler.getTask(null, fileMagr, null, null, null, units);
        t.call();
        fileMagr.close();

        //3.将编译生成的class的load 到内存,生成新对象
        URL[] urls = new URL[]{new URL("file:/" + System.getProperty("user.dir") + "/src")};
        URLClassLoader ul = new URLClassLoader(urls);
        Class c = ul.loadClass("com.proxy.$Proxy1");
        System.out.println(c);

        //4.生成代理类对象
        Constructor ctr = c.getConstructor(InvocationHandler.class);
        Object m = ctr.newInstance(h);

     return m;
    }
}

3.现在我们可以通过新建一个Tank类(被代理类),InvocationHandler的实现类TimeHandler(业务逻辑的处理) 来对代理模式进行进一步的说明。

a.目标类:Tank.java

package com.proxy;

import java.util.Random;
public class Tank implements Moveable{
    @Override
    public void move() {
        System.out.println("Tank Moving...");
        try {
            Thread.sleep(new Random().nextInt(10000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

b.TimeHandler类,实现的InvationHandler类,加上自己的代理逻辑,要加上被代理对象要调用的方法。

package com.proxy;
import java.lang.reflect.Method;
public class TimeHandler implements  InvocationHandler {
    private Object target; //定义被代理对象的一个引用
    public TimeHandler(Object target){
        super();
        this.target = target;
    }
    @Override
    public void invoke(Object o, Method m) {
        long start = System.currentTimeMillis();
        System.out.println("startTime :"+start);</span>
        try {
            m.invoke(target);//调用被代理对象的m方法
        } catch (Exception e) {
            e.printStackTrace();
        }
        long end = System.currentTimeMillis();
        System.out.println("endTime :"+end);
        System.out.println("useTime:" + (end-start));</span>

    }
}

c.Client.java测试类

package com.proxy;
public class Client {
    public static void main (String [] args) throws Exception {
        Tank t = new Tank(); //定义一个被代理的对象
        InvocationHandler h = new TimeHandler(t);
        //调用Proxy.newProxyInstance()方法生成一个代理对象。
        Moveable m = (Moveable) Proxy.newProxyInstance(Moveable.class, h);
        m.move();
    }
}

现在我们来梳理一下上面例子的逻辑

我们有一个Tank对象,Tank对象实现了Moveable接口,里面有个move方法,现在我想在Tank的move()方法前后增加一些自己的处理逻辑。

首先我们定义了自己的逻辑:这个逻辑就是,TimeHandler(自己写的代理逻辑处理类),可以将代理对象存到这个类中去我会把我定义的Tank的对象交给TimeHandler对象。

这样TimeHandler调用Tank里面的方法的时候,会先执行自己的逻辑然后Tank的方法,最后后面的逻辑。

再举一个数据库添加记录的例子。

UserMgr.java共同的接口

package com.proxy.test2;
public interface UserMgr {
    void addUser();
}

UserMgrImpl.java 被代理的类

package com.proxy.test2;
public class UserMgrImpl implements UserMgr {
    @Override
    public void addUser() {
        System.out.println("1: 插入记录到user表");
        System.out.println("2: 在另外一张表写日志");
    }
}

TransactionHandler.java ,InvocationHandler具体的实现类

package com.proxy.test2;
import com.proxy.InvocationHandler;
import java.lang.reflect.Method;
public class TransactionHandler implements InvocationHandler {
    private Object target;
    public TransactionHandler(Object target) {
        this.target = target;
    }
    @Override
    public void invoke(Object o, Method m) {
        System.out.println("Transaction Start");
        try {
            m.invoke(target);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("Transaction Commit");
    }
}

Client.java

具体的测试案例

package com.proxy.test2;
import com.proxy.InvocationHandler;
import com.proxy.Proxy;
public class Client {
    public static void main(String[] args) throws Exception {
        UserMgr mgr = new UserMgrImpl();
        InvocationHandler h = new TransactionHandler(mgr);
        //TimeHandler h2 = new TimeHandler(h);
        UserMgr u = (UserMgr) Proxy.newProxyInstance(UserMgr.class,  h);
        u.addUser();
    }
}

5.JDK动态代理的实现

JDK中的动态代理是通过2个类来实现的:

InvocationHandler:InvocationHandler 是代理实例的调用处理程序 实现的接口

方法:Object invoke(Object proxy, Method method, Object [ ] args )

三个参数的含义依次是:代理的对象,代理的方法, 方法的参数

Proxy:返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。

Static Object newProxyInstance(ClassLoader loader, Class<?> [ ] interfaces , InvocationHandler h

动态代理的作用:我不用修改原来的代码,我就可以在原来的代码中插入一些内容。也就是切面编程,AOP()Aspect oriented Programming ,

可插拔的【配置文件】,而且互相之间是可以叠加的。我们可以把上一个代理作为下一个代理的对象。

下面我们使用JDK动态代理举2个简单的案例:

PersonDao.java

public interface PersonDao {
	public void savePerson();
}

PersonDaoImpl.java

public class PersonDaoImpl implements PersonDao{
	public void savePerson() {
		System.out.println("save person");
	}
}

Transaction.java

public class Transaction {
	public void beginTransaction(){
		System.out.println("begin transaction");
	}
	public void commit(){
		System.out.println("commit");
	}
}

MyInterceptor.java

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
 * 1、引入personDao和Transaction
 * 2、完成invoke方法
 */
public class MyInterceptor implements InvocationHandler{
	private Object target;
	private Transaction transaction;
	public MyInterceptor(Object target,Transaction transaction){
		this.target = target;
		this.transaction = transaction;
	}
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		//在invoke()中做事务判断。
		if(method.getName().equals("savePerson")||method.getName().equals("updatePerson")){
			this.transaction.beginTransaction();
			method.invoke(this.target, args);//调用目标类的目标方法
			this.transaction.commit();
		}else{
			method.invoke(this.target, args);//调用目标类的目标方法
		}
		return null;
	}
}

ProxyTest.java

import java.lang.reflect.Proxy;
import org.junit.Test;
/**
 *   问题:
 *      1、拦截器中的invoke方法在什么时候被调用的?
 *         在代理对象调用方法的时候,进入了拦截器中的invoke方法
 *      2、拦截器中的method参数是什么?在什么时候由实参传递给形参的?
 *         代理对象的方法的名称是什么,method参数就是什么
 *         代理对象调用方法的时候,进入了拦截器中的invoke方法,这个时候,传递参数
 *      3、生成的代理对象实现了接口,代理对象的方法体的内容是什么?
 *         方法体的内容就是拦截器中的invoke方法体的内容
 *
 * jdkproxy的优点: 动态的产生代理对象,所以只需要用一个拦截器就可以了
 * jdkproxy的缺点: 如果在invoke方法中做事务的判断,将是一件很复杂的事情
 * 比如我们在Service接口中有20个类 ,20个方法。30个方法不需要事务,370 个方法需要事务。
 * 在invoke中做事务判断很麻烦。程序员还是写拦截器了,写拦截器中的invoke方法了,所以invoke方法还需要修改 。
 * 所以这个解决方式还是不靠谱。
 *
 * 说明: 目标类和代理类实现了共同的接口
 */
public class ProxyTest {
	@Test
	public void testProxy(){
		PersonDao target = new PersonDaoImpl();
		Transaction transaction = new Transaction();
		MyInterceptor interceptor = new MyInterceptor(target, transaction);
		/**
		 * 第一个参数: 目标类的类加载器
		 * 第二个参数: 目标类实现的所有的接口
		 * 第三个参数: 拦截器
		 */
		PersonDao personDao = (PersonDao)Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(), interceptor);
		personDao.savePerson();
	}
}

运行结果:

begin transaction
save person
commit

案例2:

SalaryManager.java

public interface SalaryManager {
	public void showSalary();
}

SalaryManagerImpl.java

public class SalaryManagerImpl implements SalaryManager{
	public void showSalary() {
		System.out.println("正在查看工资");
	}
}

Logger.java

public class Logger {
	public void logging(){
		System.out.println("logging");
	}
}

Security.java

public class Security {
	public void security(){
		System.out.println("security");
	}
}

Privilege.java

public class Privilege {
	private String access;
	public String getAccess() {
		return access;
	}
	public void setAccess(String access) {
		this.access = access;
	}
}

MyInterceptor.java

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyInterceptor implements InvocationHandler{
	private Object target;
	private Logger logger;
	private Security security;
	private Privilege privilege;
	public MyInterceptor(Object target,Logger logger, Security security, Privilege privilege) {
		super();
		this.target = target;
		this.logger = logger;
		this.security = security;
		this.privilege = privilege;
	}
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		//启动日志
		this.logger.logging();
		//安全性的框架
		this.security.security();
		//判断权限
		if(this.privilege.getAccess().equals("admin")){
			method.invoke(this.target, args);//调用目标方法
		}else{
			System.out.println("没有权限执行");
		}
		return null;
	}
}

SalaryTest.java

import java.lang.reflect.Proxy;
import org.junit.Test;

public class SalaryTest {
	@Test
	public void testSalary(){
		Logger logger = new Logger();
		Security security = new Security();
		Privilege privilege = new Privilege();<pre name="code" class="java">public interface PersonDao {
	public void savePerson();
}

privilege.setAccess("xvcz");SalaryManager target = new SalaryManagerImpl();MyInterceptor interceptor = new MyInterceptor(target, logger, security, privilege);SalaryManager salaryManager = (SalaryManager)Proxy.newProxyInstance(target.getClass().getClassLoader(),

                                                             target.getClass().getInterfaces(),interceptor);<span style="font-family: Arial, Helvetica, sans-serif;">						</span>

salaryManager.showSalary();}}


6.CGlib动态代理

cglib动态代理需要引入第三方Jar包,他与JDK代理模式的主要区别在于,JDK代理的目标类和代理类实现共同的接口,

CGLIB动态代理则是目标类是代理类的父类。

PersonDao.java

public interface PersonDao {
	public void savePerson();
}

PersonDaoImpl.java

public class PersonDaoImpl implements PersonDao{
	public void savePerson() {
		System.out.println("save person");
	}
}

Transaction.java

public class Transaction {
	public void beginTransaction(){
		System.out.println("begin transaction");
	}
	public void commit(){
		System.out.println("commit");
	}
}

MyInterceptor.java

import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
 * 1、引入personDao和Transaction
 * 2、完成invoke方法
 */
public class MyInterceptor implements MethodInterceptor{
	private Object target;
	private Transaction transaction;
	public MyInterceptor(Object target,Transaction transaction){
		this.target = target;
		this.transaction = transaction;
	}

	//产生代理对象(这是一个代码增强机制,它是在JVM内部去实现的)
	public Object createProxy(){
		Enhancer enhancer = new Enhancer();
		enhancer.setCallback(this);//this代表拦截器对象
		enhancer.setSuperclass(target.getClass());//设置代理类的父类为目标类
		return enhancer.create();
	}
	/**
	 * 该方法的内容和jdkpoxy中的invoke方法的内容是一样的
	 */
	public Object intercept(Object arg0, Method method,  Object[] args,MethodProxy arg3) throws Throwable {
		this.transaction.beginTransaction();
		method.invoke(this.target, args);
		this.transaction.commit();
		return null;
	}
}

ProxyTest.java

import org.junit.Test;
/**
 * JDK代理和cglib代理的主要区别:
 * Jdk代理的方式:目标类和代理类实现了共同的接口
 * Cglib动态代理的方式:目标类是代理类的父类
 */
public class ProxyTest {
	@Test
	public void testProxy(){
		PersonDaoImpl target = new PersonDaoImpl();
		Transaction transaction = new Transaction();
		MyInterceptor interceptor = new MyInterceptor(target, transaction);
		PersonDaoImpl proxy = (PersonDaoImpl)interceptor.createProxy();
		proxy.savePerson();
	}
}

运行结果:

begin transaction
save person
commit
时间: 2024-10-06 17:48:33

【设计模式】Proxy 代理模式的相关文章

Java设计模式——Proxy(代理)模式

Proxy(代理)模式为对象提供一个代理或者占位来控制对该对象的访问. 图像代理 使用Proxy模式的设计有时非常脆弱,它们依赖转发方法来调用其底层对象.转发可能会建立一个非常脆弱并且需要经常维护的设计. load()方法以JFrame对象为参数,用于在指定图像加载完毕之后进行回调.在执行load()方法的时候,它先以LOADING引用的图像对象为参数调用setImage(),然后重新绘制图形显示窗口,最后为自己启动一个单独的线程.而run()方法是在单独的线程中执行的,该方法根据构造器中指定的

[C++设计模式] proxy 代理模式

代理模式:为其他对象提供一种代理以控制对这个对象的访问. Proxy: 保存一个引用使得代理可以访问实体.若RealSubject和Subject的接口相同,Proxy会引用Subject,就相当于在代理类中保存一个Subject指针,该指针会指向RealSubject: 提供一个与Subject的接口相同的接口,这样代理就可以用来替代实体: 控制对实体的存取,并可能负责创建和删除它: 其它功能依赖于代理的类型,例如: 远程代理负责对请求及其参数进行编码,并向不同地址空间中的实体发送已编码的请求

Android设计模式之代理模式 Proxy

一.概述 代理模式也是平时比较常用的设计模式之一,代理模式其实就是提供了一个新的对象,实现了对真实对象的操作,或成为真实对象的替身.在日常生活中也是很常见的.例如A要租房,为了省麻烦A会去找中介,中介会替代A去筛选房子,A坐享中介筛选的结果,并且交房租也是交给中介,这就是一个典型的日常生活中代理模式的应用.平时打开网页,最先开到的一般都是文字,而图片等一些大的资源都会延迟加载,这里也是使用了代理模式. 代理模式的组成: Abstract Subject:抽象主题-声明真实主题和代理主题共同的接口

设计模式之代理模式(Proxy)摘录

23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式抽象了实例化过程,它们帮助一个系统独立于如何创建.组合和表示它的那些对象.一个类创建型模式使用继承改变被实例化的类,而一个对象创建型模式将实例化委托给另一个对象.创建型模式有两个不断出现的主旋律.第一,它们都将关于该系统使用哪些具体的类的信息封装起来.第二,它们隐藏了这些类的实例是如何被创建和放在一起的.整个系统关于这些对象所知道的是由抽象类所定义的接口.因此,创建型模式在什么被创建,谁创建它,它是怎样被创建的,以

php设计模式之Proxy(代理模式)和Facade(外观)设计模式

Proxy(代理模式)和Facade(外观)设计模式它们均为更复杂的功能提供抽象化的概念,但这两种实现抽象化的过程大不相同 Proxy案例中,所有的方法和成员变量都来自于目标对象,必要时,该代理能够对它所传递的数据进行修改或检查魔术方法使得Proxy的实现变的简单,Proxy模式的一类应用时用来记录方法的访问信息还可以利用Proxy的类确定代码的范围或调试程序中存在的问题 <?php class LoggingProxy{ private $target; //传递进去一个对象 public f

设计模式12: Proxy 代理模式(结构型模式)

Proxy 代理模式(结构型模式) 直接与间接 人们对于复杂的软件系统常常有一种处理手法,即增加一层间接层,从而对系统获得一种更为灵活.满足特定需求的解决方案.如下图,开始时,A需要和B进行3次通信,当增加一个C后,C和B只需要通信一次,A和C通信3次就好了. 动机(Motivation) 在面向对象系统中某些对象由于某种原因(比如对象创建的开销很大,或者某些操作需要安全机制,或者需要进程外的访问等),直接访问会给使用者.或者系统结构带来很多麻烦. 如果在不失去透明操作对象的同时来管理.控制这些

设计模式(十三): Proxy代理模式 -- 结构型模式

  设计模式(十一)代理模式Proxy(结构型) 1.概述 因为某个对象消耗太多资源,而且你的代码并不是每个逻辑路径都需要此对象, 你曾有过延迟创建对象的想法吗 ( if和else就是不同的两条逻辑路径) ? 你有想过限制访问某个对象,也就是说,提供一组方法给普通用户,特别方法给管理员用户?以上两种需求都非常类似,并且都需要解决一个更大的问题:你如何提供一致的接口给某个对象让它可以改变其内部功能,或者是从来不存在的功能? 可以通过引入一个新的对象,来实现对真实对象的操作或者将新的对象作为真实对象

设计模式三: 代理模式(Proxy) -- JDK的实现方式

设计模式三: 代理模式(Proxy) -- JDK的实现方式 简介 代理模式属于行为型模式的一种, 控制对其他对象的访问, 起到中介作用. 代理模式核心角色: 真实角色,代理角色; 按实现方式不同分为静态代理和动态代理两种; 意图 控制对其它对象的访问. 类图 实现 JDK自带了Proxy的实现, 下面我们先使用JDK的API来演示代理如何使用, 随后再探究Proxy的实现原理,并自己来实现Proxy. JDK代理类的使用: (InvocationHandler,Proxy) 使用JDK实现的代

C#设计模式(13)——代理模式(Proxy Pattern)

一.引言 在软件开发过程中,有些对象有时候会由于网络或其他的障碍,以至于不能够或者不能直接访问到这些对象,如果直接访问对象给系统带来不必要的复杂性,这时候可以在客户端和目标对象之间增加一层中间层,让代理对象代替目标对象,然后客户端只需要访问代理对象,由代理对象去帮我们去请求目标对象并返回结果给客户端,这样的一个解决思路就是今天要介绍的代理模式. 二.代理模式的详细介绍 代理模式按照使用目的可以分为以下几种: 远程(Remote)代理:为一个位于不同的地址空间的对象提供一个局域代表对象.这个不同的