设计模式(2)_代理模式 ————— 控制对象访问

设计模式(2)_代理模式 ————— 控制对象访问

一、动机 需求
现在有这样一个需求:有一个出版社,该出版社有一个工厂,专门用来生产制造图书,该工厂里有很多台生产制造图书的机器。每个机器有自己的位置坐标,用 int表示,机器的状态,{正在工作,暂停,故障},已经印刷了多少页图书。在出版社 在工厂 厂长的电脑屏幕上,可以随时打印出任何一台机器的报告信息(report infomation)。
下来  我们用代码实现这个需求:

PrinterMachine.java
package com.crg;
public class PrinterMachine {

        //打印机位置,及第几台打印机
        private int location;

        //打印机当前的打印页数
        private int pages;

        //打印机当前的状态
        private int state;

        public PrinterMachine(int location, int state, int pages){
                this.pages = pages;
                this.location = location;
                this.state = state;
        }

        public int getLocation(){
                return location;
        }

        public int getPages(){
                return pages;
        }

        public int getState(){
                return state;
        }

}

打印机类,可以获得该打印机的位置信息,当前页数,当前状态;
---------------------------------------------

 PrinterMonitor.java

package com.crg;
import com.crg.PrinterMachine;
public class PrinterMonitor{
        private PrinterMachine printerMachine;
        public PrinterMonitor(PrinterMachine printerMachine ){
                this.printerMachine = printerMachine;
        }

        public void report(){
                System.out.println("the PrinterMachine location is :" + printerMachine.getLocation());

                System.out.println("the PrinterMachine state is :" + printerMachine.getState());

                System.out.println("the PrinterMachine pages is :" + printerMachine.getPages());
        }
}

打印机监控类,可以打印出 那个位置的打印机的当前信息,并生成报告
---------------------------------------------

PrinterMonitorTest.java

package com.crg;
import com.crg.PrinterMachine;
import com.crg.PrinterMonitor;
public class PrinterMonitorTest{
        public static void main(String args[]){
                if(args.length < 3){
                        System.out.println("the args must be three or more");
                        System.exit(1);
                }
                int location = Integer.parseInt(args[0]);
                int state = Integer.parseInt(args[1]);
                int pages = Integer.parseInt(args[2]);
                PrinterMachine printerMachine = new PrinterMachine(location, state, pages);
                PrinterMonitor printerMonitor = new PrinterMonitor(printerMachine);
                printerMonitor.report();

        }
}

---------------------------------------------
测试类,从命令行窗口,接受三个参数,分别为 打印机位置,打印机当前状态,当前打印页数
运行效果如下:

crg@crg-pc:~/my_learning/code/proxypattern$ javac  com/crg/PrinterMonitorTest.java
crg@crg-pc:~/my_learning/code/proxypattern$ java  com/crg/PrinterMonitorTest 12 1 1126
the PrinterMachine location is :12
the PrinterMachine state is :1
the PrinterMachine pages is :1126

二、新的需求
一中的实现是在,同一台电脑,同一个JVM 上运行的,现在  又有一个新的需求,打印机PrinterMachine.java 运行在工厂的 JVM 上,而厂长要在 自己的办公室里,查看打印机监察器(PrinterMonitor.java)的 打印报告,即 打印机监察器运行在,厂长办公室的JVM上。但是呢,要想获得,打印机的详细信息报告,就必须把 PrinterMachine.java 对象传给 PrinterMonitor.java,打印机监察器才能生成报告。
解决办法如下:
不需要修改之前的代码,把远程PrinterMachine.java 在本地的代理对象 交给打印机监察器,把这个打印机在本地的代理对象(proxy),当做真正的 PrinterMachine.java 对象,其实一切的动作,是,代理对象利用网络和真正的打印机对象沟通.

这里写图片描述

三、利用java 内置 JAVA RMI 实现远程访问
1、制作远程接口

package com.crg;

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface MyRemote extends Remote {
    public String sayHello() throws RemoteException;
}

2、制作远程服务实现

package com.crg;

import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

public class MyRemoteImpl extends UnicastRemoteObject implements MyRemote {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    protected MyRemoteImpl() throws RemoteException {
        super();
    }

    @Override
    public String sayHello() throws RemoteException {
        return "Server says 'Hey'";
    }

    public static void amin(String[] args) {
        try {
            MyRemote service = new MyRemoteImpl();
            Naming.rebind("RemoteHello", service);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

3、产生 Stub(客户辅助对象,也就是远程服务对象的代理),Skeleton(服务辅助对象)
使用如下命令即可:

-rw-rw-r-- 1 crg crg  600  717 17:25 MyRemoteImpl.java
-rw-rw-r-- 1 crg crg  153  717 17:25 MyRemote.java
crg@crg-pc:~/my_learning/code/com/crg$ javac MyRemoteImpl.java
crg@crg-pc:~/my_learning/code/com/crg$ rmic -keep -v1.1 MyRemoteImpl
crg@crg-pc:~/my_learning/code/com/crg$ ll
total 40
drwxrwxr-x 2 crg crg 4096  717 17:31 ./
drwxrwxr-x 3 crg crg 4096  717 16:16 ../
-rw-rw-r-- 1 crg crg  215  717 17:31 MyRemote.class
-rw-rw-r-- 1 crg crg  771  717 17:31 MyRemoteImpl.class
-rw-rw-r-- 1 crg crg  600  717 17:25 MyRemoteImpl.java
-rw-rw-r-- 1 crg crg 1362  717 17:31 MyRemoteImpl_Skel.class
-rw-rw-r-- 1 crg crg 1260  717 17:31 MyRemoteImpl_Skel.java
-rw-rw-r-- 1 crg crg 1604  717 17:31 MyRemoteImpl_Stub.class
-rw-rw-r-- 1 crg crg 1566  717 17:31 MyRemoteImpl_Stub.java
-rw-rw-r-- 1 crg crg  153  717 17:25 MyRemote.java

4、实现客户端

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;

public class MyRemoteClient {

    public static void main(String[] args) {
        new MyRemoteClient().go();
    }
    public void go(){
        MyRemote service = null;
        try {
            service = (MyRemote) Naming.lookup("rmi://10.0.0.54/RemoteHello");
        } catch (MalformedURLException e1) {
            e1.printStackTrace();
        } catch (RemoteException e1) {
            e1.printStackTrace();
        } catch (NotBoundException e1) {
            e1.printStackTrace();
        }
        String result = null;
        try {
            result = service.sayHello();
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        System.out.println("the result is: " + result);
    }
}

5、开启一个终端 执行 rmiregistry
6、启动远程服务

crg@crg-pc:~/my_learning/code/com/crg$ java MyRemoteImpl

7、启动客户端
结果如下:

crg@crg-pc:~/Desktop/client$ java MyRemoteClient
the result is: Server says 'Hey'
crg@crg-pc:~/Desktop/client$ 

已经成功实现了 客户端远程调用  服务器端的  方法了
贴出rmic 自动生成的 MyRemoteImpl_Stub.java 和 MyRemoteImpl_Skel.java 的代码

// Stub class generated by rmic, do not edit.
// Contents subject to change without notice.

public final class MyRemoteImpl_Stub
    extends java.rmi.server.RemoteStub
    implements MyRemote, java.rmi.Remote
{
    private static final java.rmi.server.Operation[] operations = {
        new java.rmi.server.Operation("java.lang.String sayHello()")
    };

    private static final long interfaceHash = 6486744599627128933L;

    // constructors
    public MyRemoteImpl_Stub() {
        super();
    }
    public MyRemoteImpl_Stub(java.rmi.server.RemoteRef ref) {
        super(ref);
    }

    // methods from remote interfaces

    // implementation of sayHello()
    public java.lang.String sayHello()
        throws java.rmi.RemoteException
    {
        try {
            java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 0, interfaceHash);
            ref.invoke(call);
            java.lang.String $result;
            try {
                java.io.ObjectInput in = call.getInputStream();
                $result = (java.lang.String) in.readObject();
            } catch (java.io.IOException e) {
                throw new java.rmi.UnmarshalException("error unmarshalling return", e);
            } catch (java.lang.ClassNotFoundException e) {
                throw new java.rmi.UnmarshalException("error unmarshalling return", e);
            } finally {
                ref.done(call);
            }
            return $result;
        } catch (java.lang.RuntimeException e) {
            throw e;
        } catch (java.rmi.RemoteException e) {
            throw e;
        } catch (java.lang.Exception e) {
            throw new java.rmi.UnexpectedException("undeclared checked exception", e);
        }
    }
}
// Skeleton class generated by rmic, do not edit.
// Contents subject to change without notice.

public final class MyRemoteImpl_Skel
    implements java.rmi.server.Skeleton
{
    private static final java.rmi.server.Operation[] operations = {
        new java.rmi.server.Operation("java.lang.String sayHello()")
    };

    private static final long interfaceHash = 6486744599627128933L;

    public java.rmi.server.Operation[] getOperations() {
        return (java.rmi.server.Operation[]) operations.clone();
    }

    public void dispatch(java.rmi.Remote obj, java.rmi.server.RemoteCall call, int opnum, long hash)
        throws java.lang.Exception
    {
        if (hash != interfaceHash)
            throw new java.rmi.server.SkeletonMismatchException("interface hash mismatch");

        MyRemoteImpl server = (MyRemoteImpl) obj;
        switch (opnum) {
        case 0: // sayHello()
        {
            call.releaseInputStream();
            java.lang.String $result = server.sayHello();
            try {
                java.io.ObjectOutput out = call.getResultStream(true);
                out.writeObject($result);
            } catch (java.io.IOException e) {
                throw new java.rmi.MarshalException("error marshalling return", e);
            }
            break;
        }

        default:
            throw new java.rmi.UnmarshalException("invalid method number");
        }
    }
}

四、用远程代理 来改写开始那个图书工厂的例子;

源码地址:

https://github.com/aloe-all/proxy_design_pattern

先看一个逻辑思路图:

这里写图片描述

如上图所示,我们先实现,远程服务端的 打印机对象 PrinterMachine

package com.crg;

import java.rmi.Remote;
import java.rmi.RemoteException;

/**
 * 远程接口
 * @author crg
 * 方法的返回类型都必须是 可序列化的,因为要在网络传输
 *
 */
public interface PrinterMachineRemote extends Remote {
    public int getCount() throws RemoteException;
    public int getLocation() throws RemoteException;
    public State getState() throws RemoteException;
}
package com.crg;

import java.io.Serializable;

/**
 * 打印机的状态接口,把此接口序列化,所有的实现类中的 State 就可以在网络上传送了
 * @author crg
 *
 */
public interface State extends Serializable {
    public int getStateInfo();
}
package com.crg;

/**
 * 
 * State 的一个实现类,正常状态
 * @author crg
 *
 */
public class NormalState implements State {

    /**
     * PrinterMachineRemote 对象的引用,可以调用 PrinterMachine 的方法;
     * transient 修饰 PrinterMachine,告诉 JVM 不要实例化该字段
     */
    private transient PrinterMachineRemote mPrinterMachineRemote;
    @Override
    public int getStateInfo() {

        //0 代表正常状态
        return 0;
    }

}
package com.crg;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

public class PrinterMachine extends UnicastRemoteObject implements PrinterMachineRemote {

    //打印机位置,及第几台打印机
    private int location;

    //打印机当前的打印页数
    private int pages;

    //打印机当前的状态
    private State state;

    protected PrinterMachine(int location, State state, int pages) throws RemoteException {
        super();
        this.pages = pages;
        this.location = location;
        this.state = state;
    }

    @Override
    public int getCount() throws RemoteException {
        // TODO Auto-generated method stub
        return pages;
    }

    @Override
    public int getLocation() throws RemoteException {
        // TODO Auto-generated method stub
        return location;
    }

    @Override
    public State getState() throws RemoteException {
        // TODO Auto-generated method stub
        return state;
    }

}

打印机服务已经完成了。现在我们需要将它开启,好开始接受请求,首先我们要确保将他注册到 RMI registry中,好让客户端可以找到它。
服务端代码:

import java.rmi.Naming;

public class PrinterMachinePort{
        public static void main(String args[]){
            PrinterMachine currentMachine;
            int currentPages;

                if(args.length < 2){
                        System.out.println("the args must be two or more");
                        System.exit(1);
                }
                int currentMachineLocation = Integer.parseInt(args[0]);
                currentPages = Integer.parseInt(args[1]);
                try {
                    currentMachine = new PrinterMachine(currentMachineLocation, currentPages);
                    Naming.rebind(currentMachineLocation + "_PrinterMachine", currentMachine);

                } catch (Exception e) {
                    e.printStackTrace();
                }

        }
}

本地客户端代码:

package com.crg;
import java.rmi.RemoteException;

/**
 * 本地客户端监控器,运行在厂长办公室的jvm上,监控工厂的打印机
 * 
 * @author crg
 *
 */
public class PrinterMonitor{
        private PrinterMachineRemote printerMachineRemote;
        public PrinterMonitor(PrinterMachineRemote printerMachineRemote ){
                this.printerMachineRemote = printerMachineRemote;
        }

        public void report(){
                try {
                    System.out.println("the PrinterMachine state is :" + printerMachineRemote.getState().getStateInfo());
                    System.out.println("the PrinterMachine location is :" + printerMachineRemote.getLocation());
                    System.out.println("the PrinterMachine pages is :" + printerMachineRemote.getCount());
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
        }
}

客户端测试程序代码:

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;

/**
 * 监视器测试程序
 * 厂长会执行这个程序,就可以得到 ,打印机报告
 * @author crg
 *
 */
public class PrinterMachineClientTest {

    public static void main(String[] args) {

        //远程打印机 名称数组
        String[] location = {"rmi://10.0.0.54/10_PrinterMachine", "rmi://10.0.0.54/20_PrinterMachine", "rmi://10.0.0.54/30_PrinterMachine"};
        PrinterMonitor[] printerMonitors = new PrinterMonitor[location.length];

        for (int i = 0; i < location.length; i++) {
            try {

                //获得远程打印机对象,实际上得到的是远程呢个 打印机的代理 stub
                PrinterMachineRemote printerMachineRemote = (PrinterMachineRemote) Naming.lookup(location[i]);
                printerMonitors[i] = new PrinterMonitor(printerMachineRemote);

            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        for (int i = 0; i < printerMonitors.length; i++) {

            //打印报告
            printerMonitors[i].report();
        }
    }

}

编译源码

crg@crg-pc:~/workspace/RemotePrinterMachine/src/com/crg$ javac PrinterMachinePort.java

利用 java rmic 生成 代理对象

crg@crg-pc:~/workspace/RemotePrinterMachine/src/com/crg$ rmic -keep -v1.1 PrinterMachine
crg@crg-pc:~/workspace/RemotePrinterMachine/src/com/crg$ ll
total 72
drwxrwxr-x 2 crg crg 4096  723 16:52 ./
drwxrwxr-x 3 crg crg 4096  721 21:33 ../
-rw-rw-r-- 1 crg crg  327  723 16:50 NormalState.class
-rw-rw-r-- 1 crg crg  437  723 16:11 NormalState.java
-rw-rw-r-- 1 crg crg  677  723 16:50 PrinterMachine.class
-rw-rw-r-- 1 crg crg 1089  723 16:44 PrinterMachineClientTest.java
-rw-rw-r-- 1 crg crg  908  723 16:49 PrinterMachine.java
-rw-rw-r-- 1 crg crg 1110  723 16:51 PrinterMachinePort.class
-rw-rw-r-- 1 crg crg  745  723 16:40 PrinterMachinePort.java
-rw-rw-r-- 1 crg crg  295  723 16:50 PrinterMachineRemote.class
-rw-rw-r-- 1 crg crg  383  723 16:11 PrinterMachineRemote.java
-rw-rw-r-- 1 crg crg 1634  723 16:52 PrinterMachine_Skel.class
-rw-rw-r-- 1 crg crg 2006  723 16:52 PrinterMachine_Skel.java
-rw-rw-r-- 1 crg crg 2092  723 16:52 PrinterMachine_Stub.class
-rw-rw-r-- 1 crg crg 3190  723 16:52 PrinterMachine_Stub.java
-rw-rw-r-- 1 crg crg  821  723 16:11 PrinterMonitor.java
-rw-rw-r-- 1 crg crg  148  723 16:50 State.class
-rw-rw-r-- 1 crg crg  249  723 16:11 State.java

启动 rmiregistry 服务

crg@crg-pc:~/workspace/RemotePrinterMachine/src/com/crg$ rmiregistry

新开命令行窗口,启动远程打印机,启动三个不同的 打印机 服务:
这里写图片描述

这里写图片描述

crg@crg-pc:~/workspace/RemotePrinterMachine/src/com/crg$ java PrinterMachinePort 10 100

crg@crg-pc:~/workspace/RemotePrinterMachine/src/com/crg$ java PrinterMachinePort 20 2000

crg@crg-pc:~/workspace/RemotePrinterMachine/src/com/crg$ java PrinterMachinePort 30 300

然后 我在另一台 笔记本上,模拟本地客户端,笔记本上运行的是另一个 jvm 请求的是 台式机的 PrinterMachine 服务
结果如下:
这里写图片描述

这里写图片描述

本地客户端,也就是厂长的 笔记本上拿到了 打印机工厂的 打印机的 信息,远程 通过网络调用成功。
事实上 PrinterMachineClientTest.java 调用的是 PrinterMachine 在本地的 代理 PrinterMachine_Stub 来完成远程交互的。
通过调用代理的方法,远程调用可以跨过网络,返回字符串、数组、和State对象。因为我们使用的是代理,调用那方法会在远程执行。

java rmi 生成的代理文件 如下:

// Stub class generated by rmic, do not edit.
// Contents subject to change without notice.

public final class PrinterMachine_Stub
    extends java.rmi.server.RemoteStub
    implements PrinterMachineRemote, java.rmi.Remote
{
    private static final java.rmi.server.Operation[] operations = {
    new java.rmi.server.Operation("int getCount()"),
    new java.rmi.server.Operation("int getLocation()"),
    new java.rmi.server.Operation("State getState()")
    };

    private static final long interfaceHash = -5260438444927807617L;

    // constructors
    public PrinterMachine_Stub() {
    super();
    }
    public PrinterMachine_Stub(java.rmi.server.RemoteRef ref) {
    super(ref);
    }

    // methods from remote interfaces

    // implementation of getCount()
    public int getCount()
    throws java.rmi.RemoteException
    {
    try {
        java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 0, interfaceHash);
        ref.invoke(call);
        int $result;
        try {
        java.io.ObjectInput in = call.getInputStream();
        $result = in.readInt();
        } catch (java.io.IOException e) {
        throw new java.rmi.UnmarshalException("error unmarshalling return", e);
        } finally {
        ref.done(call);
        }
        return $result;
    } catch (java.lang.RuntimeException e) {
        throw e;
    } catch (java.rmi.RemoteException e) {
        throw e;
    } catch (java.lang.Exception e) {
        throw new java.rmi.UnexpectedException("undeclared checked exception", e);
    }
    }

    // implementation of getLocation()
    public int getLocation()
    throws java.rmi.RemoteException
    {
    try {
        java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 1, interfaceHash);
        ref.invoke(call);
        int $result;
        try {
        java.io.ObjectInput in = call.getInputStream();
        $result = in.readInt();
        } catch (java.io.IOException e) {
        throw new java.rmi.UnmarshalException("error unmarshalling return", e);
        } finally {
        ref.done(call);
        }
        return $result;
    } catch (java.lang.RuntimeException e) {
        throw e;
    } catch (java.rmi.RemoteException e) {
        throw e;
    } catch (java.lang.Exception e) {
        throw new java.rmi.UnexpectedException("undeclared checked exception", e);
    }
    }

    // implementation of getState()
    public State getState()
    throws java.rmi.RemoteException
    {
    try {
        java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 2, interfaceHash);
        ref.invoke(call);
        State $result;
        try {
        java.io.ObjectInput in = call.getInputStream();
        $result = (State) in.readObject();
        } catch (java.io.IOException e) {
        throw new java.rmi.UnmarshalException("error unmarshalling return", e);
        } catch (java.lang.ClassNotFoundException e) {
        throw new java.rmi.UnmarshalException("error unmarshalling return", e);
        } finally {
        ref.done(call);
        }
        return $result;
    } catch (java.lang.RuntimeException e) {
        throw e;
    } catch (java.rmi.RemoteException e) {
        throw e;
    } catch (java.lang.Exception e) {
        throw new java.rmi.UnexpectedException("undeclared checked exception", e);
    }
    }
}
// Skeleton class generated by rmic, do not edit.
// Contents subject to change without notice.

public final class PrinterMachine_Skel
    implements java.rmi.server.Skeleton
{
    private static final java.rmi.server.Operation[] operations = {
    new java.rmi.server.Operation("int getCount()"),
    new java.rmi.server.Operation("int getLocation()"),
    new java.rmi.server.Operation("State getState()")
    };

    private static final long interfaceHash = -5260438444927807617L;

    public java.rmi.server.Operation[] getOperations() {
    return (java.rmi.server.Operation[]) operations.clone();
    }

    public void dispatch(java.rmi.Remote obj, java.rmi.server.RemoteCall call, int opnum, long hash)
    throws java.lang.Exception
    {
    if (hash != interfaceHash)
        throw new java.rmi.server.SkeletonMismatchException("interface hash mismatch");

    PrinterMachine server = (PrinterMachine) obj;
    switch (opnum) {
    case 0: // getCount()
    {
        call.releaseInputStream();
        int $result = server.getCount();
        try {
        java.io.ObjectOutput out = call.getResultStream(true);
        out.writeInt($result);
        } catch (java.io.IOException e) {
        throw new java.rmi.MarshalException("error marshalling return", e);
        }
        break;
    }

    case 1: // getLocation()
    {
        call.releaseInputStream();
        int $result = server.getLocation();
        try {
        java.io.ObjectOutput out = call.getResultStream(true);
        out.writeInt($result);
        } catch (java.io.IOException e) {
        throw new java.rmi.MarshalException("error marshalling return", e);
        }
        break;
    }

    case 2: // getState()
    {
        call.releaseInputStream();
        State $result = server.getState();
        try {
        java.io.ObjectOutput out = call.getResultStream(true);
        out.writeObject($result);
        } catch (java.io.IOException e) {
        throw new java.rmi.MarshalException("error marshalling return", e);
        }
        break;
    }

    default:
        throw new java.rmi.UnmarshalException("invalid method number");
    }
    }
}

五、定义代理模式

从上面的例子可以看出,远程代理是一般代理模式的一种体现。

代理模式 :为一个对象提供一个替身或占位符以控制对这个对象的访问。
使用代理模式创建代表(representative)对象,让代表对象控制某对象的访问,被代理的对象可以是远程的对象、创建开销大的对象或需要安全控制的对象。
代理模式 uml类图

这里写图片描述

首先是 Subject,为 RealSubject 和 Proxy 提供了接口。通过实现同一接口,Proxy在RealSubject出现的地方取代它。
RealSubject 是真正做事的对象,它是被 Proxy代理控制访问的对象
Proxy 持有 RealSubject 的引用。在某些例子中,Proxy 还会负责RealSubject对象的创建和销毁。客户和 RealSubject 之间的交互必须通过 Proxy.因为代理和真实的对象 实现了相同的 接口,所以用到真实对象的地方,都可以用的代理取代。Proxy 控制 RealSubject 对象的访问。RealSubject 可以是远程对象,创建开销大,RealSubject 需要被保护。

上面的两个例子,都是远程代理,再加上 代理模式的 概念,就很容易理解了。下面看看 远程代理和 虚拟代理的比较:

这里写图片描述

1、远程代理,可以作为另一个JVM上对象的本地代表。调用代理地方法,会被代理利用网络转发到远程执行,并且结果会通过网络返回给代理,再由代理将结果转给客户;

2、虚拟代理,作为创建开销大的对象代表。虚拟代理经常等到我们真正需要创建一个对象的时候才创建它。当对象在创建前和创建中时,由虚拟代理来扮演对象的替身。对象创建后,代理就会将请求直接委托给对象。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值