zoukankan      html  css  js  c++  java
  • 代理模式(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");
            }
        }
    
    }

    测试结果:

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

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

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

  • 相关阅读:
    微博Feed流
    朋友圈
    Go命令行—compile
    Practical Go: Real world advice for writing maintainable Go programs
    Nginx Cache-Control
    Redis 主从复制
    JAVA
    Tomcat
    Tomcat
    CentOS 7
  • 原文地址:https://www.cnblogs.com/13jhzeng/p/5598093.html
Copyright © 2011-2022 走看看