zoukankan      html  css  js  c++  java
  • 代理模式

    第十一个模式:代理模式

    11.1问题引入

    远程代理的角色:

    远程代理就好比“远程对象的本地代表”。所谓“远程对象”?这是一种对象,活在不同的JVM堆中。所谓“本地代表”?这是一种可以由本地方法调用的对象,其行为会转发到远程对象中。

    image

    11.2解决方案:

    1.制作远程接口:

      远程接口定义出可以让客户远程调用的方法。客户用它作为服务的类型。Stub和实际服务都实现此接口。

    package net.dp.proxy.gumball;
    
    import java.rmi.Remote;
    import java.rmi.RemoteException;
    
    public interface GumballMachineRemote extends Remote {
        public int getCount() throws RemoteException;
    
        public String getLocation() throws RemoteException;
    
        public State getState() throws RemoteException;
    }

    我们有一个类型不是可序列化的:Stat类,现在需要修改一下:

    package net.dp.proxy.gumball;
    
    import java.io.Serializable;
    
    public interface State extends Serializable {
        public void insertQuarter();
    
        public void ejectQuarter();
    
        public void turnCrank();
    
        public void dispense();
    }

    实际上,我们需要修改状态对象,因为每一个状态对象都维持了一个对糖果机的引用,这样一来,状态对象就可以调用糖果机的方法,改变糖果机的状态。我们不希望整个糖果机都被序列化并随着State对象一起传送弄个。修正这一点:

    package net.dp.proxy.gumball;
    
    public class NoQuarterState implements State {
        /**
         * 
         */
        private static final long serialVersionUID = -6945108992684695096L;
        transient GumballMachine gumballMachine;#对于state的实现,加上transient
    
        public NoQuarterState(GumballMachine gumballMachine) {
            this.gumballMachine = gumballMachine;
        }
    
        public void insertQuarter() {
            System.out.println("You inserted a quarter");
            gumballMachine.setState(gumballMachine.getHasQuarterState());
        }
    
        public void ejectQuarter() {
            System.out.println("You haven't inserted a quarter");
        }
    
        public void turnCrank() {
            System.out.println("You turned, but there's no quarter");
        }
    
        public void dispense() {
            System.out.println("You need to pay first");
        }
    
        public String toString() {
            return "waiting for quarter";
        }
    }

    2.制作远程的实现:

       这是做实际工作的类,为远程接口中定义的远程方法提供了真正的实现。这就是客户真正想要调用方法的对象(例如,我们的GumballMachine)。

    package net.dp.proxy.gumball;
    
    import java.rmi.RemoteException;
    import java.rmi.server.UnicastRemoteObject;
    
    public class GumballMachine extends UnicastRemoteObject implements
            GumballMachineRemote {
        /**
         * 
         */
        private static final long serialVersionUID = -2838970117227273571L;
        State soldOutState;
        State noQuarterState;
        State hasQuarterState;
        State soldState;
        State winnerState;
        State state = soldOutState;
        int count = 0;
        String location;
    
        public GumballMachine(String location, int numberGumballs)
                throws RemoteException {
            soldOutState = new SoldOutState(this);
            noQuarterState = new NoQuarterState(this);
            hasQuarterState = new HasQuarterState(this);
            soldState = new SoldState(this);
            winnerState = new WinnerState(this);
    
            this.count = numberGumballs;
            if (numberGumballs > 0)
                state = noQuarterState;
            this.location = location;
        }
    
        public void insertQuarter() {
            state.insertQuarter();
        }
    
        public void ejectQuarter() {
            state.ejectQuarter();
        }
    
        public void turnCrank() {
            state.turnCrank();
            state.dispense();
        }
    
        void setState(State state) {
            this.state = state;
        }
    
        void releaseBall() {
            System.out.println("A gumball comes rolling out the slot...");
            if (count != 0) {
                count = count - 1;
            }
        }
    
        public void refill(int count) {
            this.count = count;
            state = noQuarterState;
        }
    
        public int getCount() {
            return count;
        }
    
        public State getState() {
            return state;
        }
    
        public String getLocation() {
            return location;
        }
    
        public State getSoldOutState() {
            return soldOutState;
        }
    
        public State getNoQuarterState() {
            return noQuarterState;
        }
    
        public State getHasQuarterState() {
            return hasQuarterState;
        }
    
        public State getSoldState() {
            return soldState;
        }
    
        public State getWinnerState() {
            return winnerState;
        }
    
        public String toString() {
            StringBuffer result = new StringBuffer();
            result.append("
    Mighty Gumball, Inc.");
            result.append("
    Java-enabled Standing Gumball Model #2004");
            result.append("
    Inventory: " + count + " gumball");
            if (count != 1) {
                result.append("s");
            }
            result.append("
    ");
            result.append("Machine is " + state + "
    ");
            return result.toString();
        }
    }

    糖果机服务已经实现,我们现在现在要将它装上去,好开始接受请求。首先,我们确保将它注册到RMI registry中,好让客户找到她。

    现在进行测试:

    package net.dp.proxy.gumball;
    
    import java.rmi.Naming;
    
    public class GumballMachineTestDrive {
    
        public static void main(String[] args) {
            GumballMachineRemote gumballMachine = null;
            int count;
    
            if (args.length < 2) {
                System.out.println("GumballMachine <name> <inventory>");
                System.exit(1);
            }
    
            try {
                count = Integer.parseInt(args[1]);
    
                gumballMachine = new GumballMachine(args[0], count);
                Naming.rebind("//" + args[0] + "/gumballmachine", gumballMachine);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    然后,进行测试:

    image

    3.利用rmic产生的Stub和skeleton

      这是客户和服务的辅助类。你不需要创建这些类。

    4.启动RMI registry(rimregistry)

      rmireistry就像电话簿,客户可以从中查到代理的位置。

    5.开始远程服务

    必须启动服务对象。

    现在是GumballMonitor客户端:

    package net.dp.proxy.gumball;
    
    import java.rmi.RemoteException;
    
    public class GumballMonitor {
        GumballMachineRemote machine;
    
        public GumballMonitor(GumballMachineRemote machine) {
            this.machine = machine;
        }
    
        public void report() {
            try {
                System.out.println("Gumball Machine: " + machine.getLocation());
                System.out.println("Current inventory: " + machine.getCount()
                        + " gumballs");
                System.out.println("Current state: " + machine.getState());
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }

    编写监视器测试程序:

    image

    再详细的查看:

    image

    11.3引入代理模式:

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

    11.4介绍虚拟代理:

    不同之处:

    image

    image

    例子:显示CD封面类图:

    image

    工作流程:

    image

    编写虚拟ImageProxy:

    package net.dp.proxy.virtualproxy;
    
    import java.awt.Component;
    import java.awt.Graphics;
    import java.net.URL;
    
    import javax.swing.Icon;
    import javax.swing.ImageIcon;
    
    class ImageProxy implements Icon {
        ImageIcon imageIcon;
        URL imageURL;
        Thread retrievalThread;
        boolean retrieving = false;
         
        public ImageProxy(URL url) { imageURL = url; }
         
        public int getIconWidth() {
            if (imageIcon != null) {
                return imageIcon.getIconWidth();
            } else {
                return 800;
            }
        }
     
        public int getIconHeight() {
            if (imageIcon != null) {
                return imageIcon.getIconHeight();
            } else {
                return 600;
            }
        }
         
        public void paintIcon(final Component c, Graphics  g, int x,  int y) {
            if (imageIcon != null) {
                imageIcon.paintIcon(c, g, x, y);
            } else {
                g.drawString("Loading CD cover, please wait...", x+300, y+190);
                if (!retrieving) {
                    retrieving = true;
    
                    retrievalThread = new Thread(new Runnable() {
                        public void run() {
                            try {
                                imageIcon = new ImageIcon(imageURL, "CD Cover");
                                c.repaint();
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    });
                    retrievalThread.start();
                }
            }
        }
    }
    package net.dp.proxy.virtualproxy;
    
    import java.awt.Graphics;
    
    import javax.swing.Icon;
    import javax.swing.JComponent;
    
    class ImageComponent extends JComponent {
        /**
         * 
         */
        private static final long serialVersionUID = -4028999850832876573L;
        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);
        }
    }
    package net.dp.proxy.virtualproxy;
    
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.net.MalformedURLException;
    import java.net.URL;
    import java.util.Enumeration;
    import java.util.Hashtable;
    
    import javax.swing.Icon;
    import javax.swing.JFrame;
    import javax.swing.JMenu;
    import javax.swing.JMenuBar;
    import javax.swing.JMenuItem;
    
    public class ImageProxyTestDrive {
        ImageComponent imageComponent;
        JFrame frame = new JFrame("CD Cover Viewer");
        JMenuBar menuBar;
        JMenu menu;
        Hashtable<String, String> cds = new Hashtable<String, String>();
    
        public static void main(String[] args) throws Exception {
            @SuppressWarnings("unused")
            ImageProxyTestDrive testDrive = new ImageProxyTestDrive();
        }
    
        public ImageProxyTestDrive() throws Exception {
            cds.put("Ambient: Music for Airports",
                    "http://images.amazon.com/images/P/B000003S2K.01.LZZZZZZZ.jpg");
            cds.put("Buddha Bar",
                    "http://images.amazon.com/images/P/B00009XBYK.01.LZZZZZZZ.jpg");
            cds.put("Ima",
                    "http://images.amazon.com/images/P/B000005IRM.01.LZZZZZZZ.jpg");
            cds.put("Karma",
                    "http://images.amazon.com/images/P/B000005DCB.01.LZZZZZZZ.gif");
            cds.put("MCMXC A.D.",
                    "http://images.amazon.com/images/P/B000002URV.01.LZZZZZZZ.jpg");
            cds.put("Northern Exposure",
                    "http://images.amazon.com/images/P/B000003SFN.01.LZZZZZZZ.jpg");
            cds.put("Selected Ambient Works, Vol. 2",
                    "http://images.amazon.com/images/P/B000002MNZ.01.LZZZZZZZ.jpg");
    
            URL initialURL = new URL((String) cds
                    .get("Selected Ambient Works, Vol. 2"));
            menuBar = new JMenuBar();
            menu = new JMenu("Favorite CDs");
            menuBar.add(menu);
            frame.setJMenuBar(menuBar);
    
            for (Enumeration<String> e = cds.keys(); e.hasMoreElements();) {
                String name = (String) e.nextElement();
                JMenuItem menuItem = new JMenuItem(name);
                menu.add(menuItem);
                menuItem.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent event) {
                        imageComponent.setIcon(new ImageProxy(getCDUrl(event
                                .getActionCommand())));
                        frame.repaint();
                    }
                });
            }
    
            // set up frame and menus
    
            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;
            }
        }
    }

    11.5小结:

    image

  • 相关阅读:
    jquery处理鼠标左中右键事件
    bootstrap弹出框
    移动端去掉a标签点击时出现的背景
    sessionStorage
    页面滑动到最下面,执行代码
    判断页面时向上滚动还是向下滚动
    sql 时间查询 /sql中判断更新或者插入/查询一年所有双休日
    求取最大值
    Repeater 获取数据值
    加载完毕后执行计算
  • 原文地址:https://www.cnblogs.com/maverick-fu/p/4504549.html
Copyright © 2011-2022 走看看