代理模式(Proxy Pattern)

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

一般代理模式类图:

远程代理:Java RMI

RMI:远程方法调用,提供客户辅助对象和服务辅助对象,为客户辅助对象创建和服务对象相同的方法。RMI的好处在于不必亲自写任何网络或I/O代码。客户程序调用远程方法(真正的服务)就和在运行在客户自己本地JVM上对对象进行正常方法调用一样。

RMI的查找服务可以用来寻找和访问远程对象。

RMI调用模型:

外部观察RMI过程:

1.运行服务器,服务器实现类回去实例化一个服务的实例,并将这个服务注册到RMI registry。注册之后,这个服务就可以供客户调用了。

2.运行客户端,客户端通过查找服务(lookup service),根据服务的名字,找到对应的服务。

3.现在在客户端就可以调用远程服务器的方法了。

在外部观察RMI的过程,并不能知道其实是代理在背后起作用。

内部观察RMI过程:

1.服务器实例化服务实例的同时,实例化一个RMI Skeleton代理和RMI Stub代理

2.当客户端通过查找服务,找到该服务,服务器将Stub通过网络传给客户,此时是二进制流,客户端需反序列成Stub

3.客户调用客户对象的方法会调用Stub的同名方法,Stub代理打包调用信息,通过网络转给Skeleton,Skeleton把信息解包,找出被调用的方法(以及方法在哪个对象内),然后调用真正的服务对象上的真正方法

4.服务对象上的方法被调用,将结果返回给Skeleton

5.Skeleton把方法返回信息打包,然后通过网络转给Stub

6.Stub将信息解包,返回给客户对象

一个简单的RMI例子:

服务器端:

public interface MyRemote extends Remote {//Remote接口是jdk提供的一个接口
    public String sayHello() throws RemoteException;
}

public class MyRemoteImpl extends UnicastRemoteObject implements MyRemote {//实现UnicastRemoteObject是创建远程对象的最容易方法,由jdk提供
                                           
    protected MyRemoteImpl() throws RemoteException {
        super();
        // TODO Auto-generated constructor stub
    }

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

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        try {
            MyRemote service = new MyRemoteImpl();
            Registry registry = LocateRegistry.createRegistry(1099);//端口号1099
            registry.bind("RemoteHello", service);//注册服务对象,服务名字为RemoteHello
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}

客户端:

public class Client {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        try {
            MyRemote service = (MyRemote) Naming.lookup("rmi://127.0.0.1:1099/RemoteHello");//127.0.0.1代表本机,RemoteHello是服务的名字

            String s = service.sayHello();//在客户端调用远程对象的方法,返回一个String
            System.out.println(s);将方法返回值打印出来
        } catch(Exception e) {
            e.printStackTrace();
        }

    }

}

测试结果:

一个小问题:为了在网络传输,远程方法的返回值都必须是可序列化的,所以需要实现Serializable接口,例子中的返回值是String,所以没有问题,如果是自定义的对象,那么需要实现Serializable接口才能正常运行。

RMI类图模型:

虚拟代理:

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

现在有一个应用是从网站取得图像,然后显示出来,限制在于带宽和网络负载,下载需要一些时间,但是在等待图像加载的时候,应该显示一些东西。我们不希望等待图像的时候整个应用被挂起,一旦加载完成,刚才显示的东西应该消失,图像显示出来。

设计类图:

public class ImageComponent extends JComponent {
    private Icon icon;

    public ImageComponent(Icon icon) {
        this.icon = icon;
    }

    public void setIcon(Icon icon) {
        this.icon = icon;
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        int w = icon.getIconWidth();
        int h = icon.getIconHeight();
        int x = (800 - w)/2;
        int y = (600 - h)/2;
        icon.paintIcon(this, g, x, y);
    }
}

public class ImageProxy implements Icon {
    ImageIcon imageIcon;
    URL imageURL;
    Thread retrievalThread;
    boolean retrieving = false;

    public ImageProxy(URL url) {
        imageURL = url;
    }

    @Override
    public void paintIcon(Component c, Graphics g, int x, int y) {
        if(imageIcon != null) {//如果已经加载出来,即imageIcon实例化了
            imageIcon.paintIcon(c, g, x, y);//将请求转给真正的对象
        } else {
            g.drawString("Loading, please wait...", x+300, y+190);//否则显示一个提示字符串
            if(!retrieving) {//这个变量的目的是只开一个线程去实例化真正的对象
                retrieving = true;
                retrievalThread = new Thread(new Runnable() {//如果未加载出来,开一个新线程加载,避免程序被挂起
                    @Override
                    public void run() {
                        try {
                            imageIcon = new ImageIcon(imageURL, "CD Cover");
                            c.repaint();
                        } catch(Exception e) {
                            e.printStackTrace();
                        }

                    }

                });
                retrievalThread.start();
            }
        }

    }

    @Override
    public int getIconWidth() {
        if(imageIcon != null) {
            return imageIcon.getIconWidth();
        } else {
            return 800;
        }
    }

    @Override
    public int getIconHeight() {
        if(imageIcon != null) {
            return imageIcon.getIconHeight();
        } else {
            return 600;
        }
    }
}

public class Test {
    ImageComponent imageComponent;
    JFrame frame = new JFrame("CD Cover View");
    JMenuBar menuBar;
    JMenu menu;
    Hashtable cds = new Hashtable();

    public Test() throws Exception {
        cds.put("Ambient:Music for Airports", "http://images.amazon.com/images/P/B000003S2L.01.LZZZZZZZ.jpg");
        cds.put("Ima", "http://images.amazon.com/images/P/B000005IRM.01.LZZZZZZZ.jpg");

        URL initialURL = new URL((String)cds.get("Ima"));
        menuBar = new JMenuBar();
        menu = new JMenu("Favorite CDs");
        menuBar.add(menu);
        frame.setJMenuBar(menuBar);
        for(Enumeration e = cds.keys(); e.hasMoreElements();) {
            String name = (String)e.nextElement();
            JMenuItem menuItem = new JMenuItem(name);
            menu.add(menuItem);
            menuItem.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    imageComponent.setIcon(new ImageProxy(getCDUrl(e.getActionCommand())));
                    frame.repaint();
                }
            });
        }
        Icon icon = new ImageProxy(initialURL);
        imageComponent = new ImageComponent(icon);
        frame.getContentPane().add(imageComponent);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(800, 600);
        frame.setVisible(true);
    }

    URL getCDUrl(String name) {
        try {
            return new URL((String)cds.get(name));
        } catch(MalformedURLException e) {
            e.printStackTrace();
            return null;
        }
    }

    public static void main(String[] args) throws Exception {
        Test t = new Test();
    }

}

测试结果:

图像还未加载成功:

图像加载成功:

保护代理:

例子代码:

public interface PersonBean {
    String getName();
    String getGender();
    String getInterest();
    int getHotOrNotRating();

    void setName(String name);
    void setGender(String gender);
    void setInterest(String interests);
    void setHotOrNotRating(int rating);
}

public class PersonBeanImpl implements PersonBean {
    String name;
    String gender;
    String interest;
    int rating;
    int ratingCount = 0;

    public PersonBeanImpl(String name, String gender, String interest) {
        this.name = name;
        this.gender = gender;
        this.interest = interest;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public String getGender() {
        return gender;
    }

    @Override
    public String getInterest() {
        return interest;
    }

    @Override
    public int getHotOrNotRating() {
        if(ratingCount == 0) return 0;
        return (rating/ratingCount);
    }

    @Override
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public void setGender(String gender) {
        this.gender = gender;
    }

    @Override
    public void setInterest(String interest) {
        this.interest = interest;
    }

    @Override
    public void setHotOrNotRating(int rating) {
        this.rating += rating;
        ratingCount++;
    }

}

public class OwnerInvocationHandler implements InvocationHandler {
    PersonBean person;

    public OwnerInvocationHandler(PersonBean person) {
        this.person = person;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws IllegalAccessException {
        try {
            if(method.getName().startsWith("get")) {
                return method.invoke(person, args);
            } else if(method.getName().equals("setHotOrNotRating")) {
                throw new IllegalAccessException();
            } else if(method.getName().startsWith("set")) {
                return method.invoke(person, args);
            }
        } catch(InvocationTargetException e) {
            e.printStackTrace();
        }

        return null;
    }

}

public class NonOwnerInvocationHandler implements InvocationHandler {
    PersonBean person;

    public NonOwnerInvocationHandler(PersonBean person) {
        this.person = person;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws IllegalAccessException {
        try {
            if(method.getName().startsWith("get") || method.getName().equals("setHotOrNotRating")) {
                return method.invoke(person, args);
            } else {
                throw new IllegalAccessException();
            }
        } catch(InvocationTargetException e) {
            e.printStackTrace();
        }
        return null;
    }

}

public class TestDrive {
    static PersonBean getOwnerProxy(PersonBean person) {
        return (PersonBean)Proxy.newProxyInstance(person.getClass().getClassLoader(), person.getClass().getInterfaces(), new OwnerInvocationHandler(person));
    }

    static PersonBean getNonOwnerProxy(PersonBean person) {
        return (PersonBean)Proxy.newProxyInstance(person.getClass().getClassLoader(), person.getClass().getInterfaces(), new NonOwnerInvocationHandler(person));
    }

    public static void main(String[] args) {
        PersonBean joe = new PersonBeanImpl("joe", "male", "football");

        PersonBean ownerProxy = getOwnerProxy(joe);
        ownerProxy.setInterest("ping pong");
        System.out.println("owner setInterest");
        try {
            ownerProxy.setHotOrNotRating(10);
        } catch(Exception e) {
            System.out.println("setHotOrRating faild");
        }
        System.out.println("rating:" + ownerProxy.getHotOrNotRating());

        PersonBean nonOwnerProxy = getNonOwnerProxy(joe);
        nonOwnerProxy.setHotOrNotRating(10);
        try {
            nonOwnerProxy.setInterest("basketball");
        } catch(Exception e) {
            System.out.println("setInterest faild");
        }
    }

}

测试结果:

本文提到三个代理:远程代理、虚拟代理、保护代理。

在实际应用中,代理模式的变体有很多,如还有防火墙代理,写入时复制代理,缓存代理...

不变的是:它们都是为了控制对象的访问。

时间: 2024-10-12 16:19:14

代理模式(Proxy Pattern)的相关文章

设计模式 - 代理模式(proxy pattern) 未使用代理模式 详解

代理模式(proxy pattern) 未使用代理模式 详解 本文地址: http://blog.csdn.net/caroline_wendy 部分代码参考: http://blog.csdn.net/caroline_wendy/article/details/37698747 如果需要监控(monitor)类的某些状态, 则需要编写一个监控类, 并同过监控类进行监控. 但仅仅局限于本地, 如果需要远程监控, 则需要使用代理模式(proxy pattern). 具体方法: 1. 类中需要提供

设计模式之代理模式---Proxy Pattern

模式的定义 代理模式(Proxy Pattern)也叫做委托模式,定义如下: Provide a surrogate or placeholder for another object to control access to is. 为其他对象提供一种代理以控制对这个对象的访问. 类型 结构类 模式的使用场景 想想现实世界中,打官司为什么要找个律师?因为你不想参与中间过程的是是非非,只要完成自己的工作就可以,其它的事情比如事前调查,事后追查都可以由律师来负责,这就可以减少你的负担.代理模式使用

设计模式(结构型)之代理模式(Proxy Pattern)

PS一句:最终还是选择CSDN来整理发表这几年的知识点,该文章平行迁移到CSDN.因为CSDN也支持MarkDown语法了,牛逼啊! [工匠若水 http://blog.csdn.net/yanbober] 阅读前一篇<设计模式(结构型)之享元模式(Flyweight Pattern)>http://blog.csdn.net/yanbober/article/details/45477551 概述 代理模式是常用的结构型设计模式之一,当无法直接访问某个对象或访问某个对象存在困难时可以通过一个

二十三种设计模式[12] - 代理模式(Proxy Pattern)

前言 代理模式,属于对象结构型模式.在<设计模式 - 可复用的面向对象软件>一书中将之描述为" 为其它对象提供一种代理以控制对这个对象的访问 ". 在代理模式中,通常使用一个类来代表另一个类的功能,并由这个代理对象去控制原对象的引用. 结构 Subjuet(公共接口):代理类和被代理类的公共接口,保证任何使用目标的地方都可以被代理类替换: RealSubject(被代理类):代理类所代表的目标类: Proxy(代理类):包含对目标类的引用,目标类的封装: 场景 在日常生活中

代理模式(Proxy Pattern)

一.概述在软件开发中,有些对象由于创建成本高.访问时需要与其它进程交互等原因,直接访问会造成系统速度慢.复杂度增大等问题.这时可以使用代理模式,给系统增加一层间接层,通过间接层访问对象,从而达到隐藏系统复杂性.提高系统性能的目的.二.代理模式代理模式为其他对象提供一种代理以控制对这个对象的访问.其结构图如下: Subject定义了RealSubject和Proxy共用的接口,使得在任何使用RealSubject的地方都可以使用Proxy abstract class Subject { publ

设计模式之(二)---代理模式Proxy Pattern

什么是代理模式呢?我很忙,忙的没空理你,那你要找我呢就先找我的代理人吧,那代理人总要知道 被代理人能做哪些事情不能做哪些事情吧,那就是两个人具备同一个接口,代理人虽然不能干活,但是被 代理的人能干活呀. 比如西门庆找潘金莲,那潘金莲不好意思答复呀,咋办,找那个王婆做代理,表现在程序上时这样的: 先定义一种类型的女人(接口): package com.fc.Proxy; public interface KindWoman { public void makeEyesWithMan(); //抛媚

13.代理模式(Proxy Pattern)

using System; namespace ConsoleApplication6 { class Program { static void Main(string[] args) { // 创建一个代理对象并发出请求 Person proxy = new Friend(); proxy.BuyProduct(); Console.Read(); } } // 抽象主题角色 public abstract class Person { public abstract void BuyPro

设计模式 -- 代理模式 (proxy Pattern)

定义: 为其他对象提供一种代理以控制对这个对象的访问: 角色: 1,抽象主题类,(接口或者抽象类),抽象真实主题和代理的共有方法(如下Subject类): 2,具体实现的主题类,继承或者实现抽象主题类的抽象方法(如下RealSubject类): 3,代理类,继承实现抽象主题类,并提供传递具体实现主题类,在实现方法里面调用具体实现的主题类(如下ProxySubject类); Subject.java /** * Created by Administrator on 2016/8/31. */ p

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

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

ES6中的代理模式-----Proxy

什么是代理模式 代理模式(英语:Proxy Pattern)是程序设计中的一种设计模式. 所谓的代理者是指一个类别可以作为其它东西的接口.代理者可以作任何东西的接口:网络连接.内存中的大对象.文件或其它昂贵或无法复制的资源. 著名的代理模式例子为引用计数(英语:reference counting)指针对象. 当一个复杂对象的多份副本须存在时,代理模式可以结合享元模式以减少内存用量.典型作法是创建一个复杂对象及多个代理者,每个代理者会引用到原本的复杂对象.而作用在代理者的运算会转送到原本对象.一