Java設計模式十八:代理模式(Proxy)


為另一個對象提供一個替身或占位符以控制對這個對象的訪問,簡而言之就是用一個對象來代表另一個對象。
類圖:


簡單例子:有個接口Italk,people對象實現這個接口的talk()方法,有些想另外加入sing()方法,所以增加代理類talkProxy,實現兩個方法.
public interface ITalk
{
    public void talk(String msg);
}

public class People implements ITalk
{
    @Override
    public void talk(final String msg)
    {
        System.out.println(msg);
    }
}

public class TalkProxy implements ITalk
{
    ITalk italk;

    public TalkProxy(final ITalk italk)
    {
        this.italk = italk;
    }

    @Override
    public void talk(final String msg)
    {
        this.italk.talk(msg);
    }

    public void sing(final String songName)
    {
        System.out.println("Song Name:" + songName);
    }
}

public class Client
{
    public static void main(final String[] args)
    {
        final People people = new People();
        people.talk("I can't sing");

        final TalkProxy proxy = new TalkProxy(people);
        proxy.talk("I can talk");
        proxy.sing("I can sing");
    }
}

結果:
I can't sing
I can talk
Song Name:I can sing

常見的代理:
1. 遠程代理(Remote Proxy):為一個位於不同的地址空間的對象提供一個本地的代理對象。這個不同的地址空間可以是在同一台主機中,也

可是在另一台主機中,遠程代理又叫做大使(Ambassador)。
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface MyRemote extends Remote
{
    public String getUserName(String userId) throws RemoteException;
}

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public class MyRemoteImp extends UnicastRemoteObject implements MyRemote
{
    protected MyRemoteImp() throws RemoteException
    {
        
    }

    public String getUserName(String userId) throws RemoteException
    {
        return userId + "/myName is Cherry";
    }

}

在cmd中輸入:
javac MyRemote.java
javac MyRemoteImp.java
rmic MyRemoteImp
生成類的class文件及MyRemoteImp_Stub.class文件


import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.RemoteException;
public class MyRemoteServer
{
    public static void main(final String[] args)
    {
        // YTODO Auto-generated method stub
        MyRemote remote;
        try
        {
            remote = new MyRemoteImp();
            Naming.rebind("RemoteService", remote);
        }
        catch (final RemoteException e)
        {
            // YTODO Auto-generated catch block
            e.printStackTrace();
        }
        catch (final MalformedURLException e)
        {
            // YTODO Auto-generated catch block
            e.printStackTrace();
        }

    }

}

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
public class MyRemoteClient
{
    public static void main(final String[] args)
    {
        try
        {
            final MyRemote service = (MyRemote) Naming.lookup("rmi://127.0.0.1/RemoteService");
            final String name = service.getUserName("my id is 001");
            System.out.println(name);
        }
        catch (final MalformedURLException e)
        {
            e.printStackTrace();
        }
        catch (final RemoteException e)
        {
            e.printStackTrace();
        }
        catch (final NotBoundException e)
        {
            e.printStackTrace();
        }
    }

}

在dos下運行rmiregistry, 這個命令是開啟RMI注冊服務, 開啟以后我們的server程序才能調用rebing方法發布我們的類,然后運行server程序

.
javac MyRemoteServer.java
java MyRemoteServer

start rmiregistry
javac MyRemoteServer.java
java MyRemoteServer

再打開一個dos運行客戶端代碼
javac MyRemoteClient.java
java MyRemoteClient

輸出:my id is 001/myName is Cherry

這里一共有三個dos窗口, 當執行start rmiregistry時,會彈出它的窗口,當執行java MyRemoteServer的服務器端窗口,執行java

MyRemoteClient的客戶端窗口(這里的rmiregistry.exe的窗口需要一直打開,否則無法調用服務器端).

2. 虛擬代理(Virtual Proxy):根據需要創建開銷很大的對象。如果需要創建一個資源消耗較大的對象,先創建一個消耗相對較小的對象來表

示,真實對象只會在需要時才會被真正創建。
public interface Image
{
    public void show();
}

public class BigImage implements Image
{
    public BigImage()
    {
        //Thread.sleep(3000);//for simulating to load the big images
        System.out.println("create the big images");
    }

    @Override
    public void show()
    {
        System.out.println("show the big images");
    }
}

public class ImageProxy implements Image
{
    Image image;

    public ImageProxy()
    {

    }

    public ImageProxy(final Image image)
    {
        this.image = image;
    }

    @Override
    public void show()
    {
        if (this.image == null)
        {
            this.image = new BigImage();
        }
        this.image.show();
    }
}

public class Client
{
    public static void main(final String[] args)
    {
        System.out.println("big image:");
        final Image bigImage = new BigImage();
        bigImage.show();

        System.out.println("image proxy:");
        final Image imageProxy = new ImageProxy();
        imageProxy.show();
    }
}
結果:
create the big images
show the big images
image proxy:
create the big images
show the big images

3. Copy-on-Write代理: 虛擬代理的一種,把復制(克隆)拖延到只有在客戶端需要時,才真正采取行動。

4. 保護代理(Protection or Access Proxy):控制對原始對象的訪問。保護代理用於對象應該有不同的訪問權限的時候。

5. 智能指引(Smart Reference):取代了簡單的指針,它在訪問對象時執行一些附加操作.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM