`

代理模式Image Proxies(一、最朴素实现)

阅读更多

A Classic Example:  Image Proxies

       以下是最朴素的代理模式实现,其中只有“代理”的思想,但并不是真正的代理。



 

       一个ImageIconProxy proxy实例被封装在JFrame frame中,且他们都是ShowProxy属性。

       点击“Load按钮”触发调用proxy.load(frame),该方法重新设置proxy内部current对象为ImageIcon LOADING,立即repaint窗口frame,将短暂显示Loading…。然后,该方法启动独立线程加载最终图片,这个独立线程也是通过重新设置proxy内部current对象,然后重绘(调用callbackFrame.pack())的方式。

       重绘通过ImageIconProxy实现以下三个方法:

       getIconHeight()getIconWidth()paintIcon(...),实现时只需将ImageIconProxycurrent指示的图片绘制出来。注意到,ImageIconProxy继承了ImageIcon,并实现了该父类的此三种方法后就可以被调用者当作一个ImageIcon实例使用了。

 

代码:

文件一:ShowProxy.java

package app.proxy;

 

public class ShowProxy implements ActionListener {

    private ImageIconProxy proxy = new ImageIconProxy("images/fest.jpg");

    private JFrame frame;

    private JButton loadButton;

 

    /*********************************Load按钮*******************************/

    protected JButton loadButton() {

        if (loadButton == null) {

            loadButton = new JButton("Load");

            loadButton.addActionListener(this);//ShowProxy实现监听按钮

            loadButton.setFont(SwingFacade.getStandardFont());

        }

        return loadButton;

    }

   

    /**

     * 当用户点击按钮时,触发监听器执行这个函数

     * Start loading the image and disable the Load button.

     */

    public void actionPerformed(ActionEvent e) {

    /*

     * 理解P117这句话:

     * The proxy does its work by judiciously forwarding requests to

     * the underlying object that the proxy controls access to.

     */

        proxy.load(frame);    //这里是关键!!!

        loadButton().setEnabled(false);

    }

 

    /*********************************JPanel**********************************/

    protected JPanel mainPanel() {

        JPanel p = new JPanel();

        p.setLayout(new BorderLayout());

       

        /*

         * ImageIconProxy被封装在JLabel内部-->

         * JLabel(Icon);

         * ImageIconProxy extends ImageIcon;

         * ImageIcon implements javax.swing.Icon

         */

        p.add("Center", new JLabel(proxy));

        /*

         * 添加按钮到JPanel,点击按钮后调用方法:

         * proxy.load(frame);

         */

        p.add("South", loadButton());

        return p;

    }

    /*********************************main()**********************************/

    public static void main(String[] args) {

        ShowProxy sp = new ShowProxy();

        sp.frame = SwingFacade.launch(sp.mainPanel(), " Proxy");

        /*

         * 1. com.oozinoz.ui.SwingFacade:

         * This utility class provides an interface that makes

         * the Swing subsystem easy to use.

         *

         * 2. JFrame com.oozinoz.ui.SwingFacade.launch(Component c, String title):

         * Display the given component within a frame.

         */

    }

}

 

文件二:ImageIconProxy.java  -->  可以看做是代理

public class ImageIconProxy extends ImageIcon implements Runnable {

    static final ImageIcon ABSENT = new ImageIcon(ClassLoader

            .getSystemResource("images/absent.jpg"));

    static final ImageIcon LOADING = new ImageIcon(ClassLoader

            .getSystemResource("images/loading.jpg"));

   

    ImageIcon current = ABSENT;//只会显示current指示的图片

    protected String filename;

    protected JFrame callbackFrame;

 

    public ImageIconProxy(String filename) {

        super(ABSENT.getImage());// Image javax.swing.ImageIcon.getImage()

        this.filename = filename;

    }

 

    public void load(JFrame callbackFrame) {

        //1、将图片设置为LOADING

        this.callbackFrame = callbackFrame;

        current = LOADING;

        callbackFrame.repaint();

       

        //2、利用一个独立线程,加载最终图片

        /*

         * 仅当点击Load按钮时,触发proxy.load(frame);(在类ShowProxy)

         * 初始时,ImageIconProxy被实例化,但并没有启动它的线程

         */

        new Thread(this).start();

    }

 

    public void run() {

        current = new ImageIcon(ClassLoader.getSystemResource(filename));

        /*

         * void java.awt.Window.pack():

         * Causes this Window to be sized to fit the preferred size and

         * layouts of its subcomponents...

         */

        callbackFrame.pack();

    }

 

    public int getIconHeight() {

        return current.getIconHeight();

    }

 

    public int getIconWidth() {

        return current.getIconWidth();

    }

 

    /**

     * Paint the Icon

     */

    public synchronized void paintIcon(Component c, Graphics g, int x, int y) {

        current.paintIcon(c, g, x, y);

    }

}

 

Q&A:

The ImageIconProxy class is not a well-designed, reusable component. Point out two problems with the design.

 

1.     Forwarding only a subset of calls to an underlying ImageIcon object is dangerous. The ImageIconProxy class inherits a dozen fields and at least 25 methods from the ImageIcon class. To be a true proxy, the ImageIconProxy object needs to forward most or all of these calls. Thorough forwarding would require many potentially erroneous methods, and this code would require maintenance as the ImageIcon class and its superclasses change over time.

     (ImageIconProxy对象)仅向底层的ImageIcon对象转发部分调用是危险的。ImageIconProxy对象从ImageIcon类集成了一打域和至少25个方法。作为一个真正的代理,ImageIconProxy必须转发大多数或全部调用。“完全转发”可能导致潜在错误,而且这样的代码要求随ImageIcon类及其父类改变而改变。

 

2.     You might question whether the “Absent” image and the desired image are in the right places in the design. It might make more sense to have the images passed in rather than making the class responsible for finding them.

 

      你或许对"Absent"图片和最终图片的位置争取性存在疑问。或许让这些图片被传入,而非让ImageIconProxy来负责他们,更加合理。

 

 

见附件中使用oozinoz提供的包简单实现窗口的代码

 

 

  • 大小: 28.2 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics