在构造函数中调用诸如Swing的add()之类的可重写方法 [英] Calling overridable methods like Swing's add() in constructor

查看:71
本文介绍了在构造函数中调用诸如Swing的add()之类的可重写方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道从构造函数调用可重写方法是一个坏主意.但是我也看到它在Swing中随处可见,像 add(new JLabel("Something")); 这样的代码始终在构造函数中出现.

I know that calling overridable methods from constructors is a bad idea. But I also see that it's being done everywhere with Swing, where code like add(new JLabel("Something")); occurs in constructors all the time.

例如,以NetBeans IDE为例.对于构造函数中的可重写调用非常挑剔.但是,当它生成Swing代码时,会将所有这些 add()方法调用放入一个 initializeComponents()方法中……然后从构造函数中调用它!隐藏问题并禁用警告的一种好方法(NetBeans没有从构造函数调用调用可重写方法的私有方法"警告).但这并不是解决问题的真正方法.

Take NetBeans IDE, for example. It is very picky about overridable calls in constructors. And yet, when it generates Swing code, it puts all those add() method calls into an initializeComponents() method... which is then called from the constructor! A nice way to hide a problem and disable the warning (NetBeans doesn't have a "a private method that calls overridable methods is called from a constructor" warning). But not really a way to solve the problem.

这是怎么回事?我已经做了很长时间了,但是对此总是感到不安.除了制作一个额外的 init()方法(而且不要忘记每次都调用它,这很无聊)之外,还有没有更好的初始化Swing容器的方法?

What's going on here? I've been doing it for ages, but always had an uneasy feeling about this. Is there a better way of initializing Swing containers, except for making an additional init() method (and not forgetting to call it every time, which is kind of boring)?

示例

这是一个关于如何出错的极其人为的例子:

Here is an extremely contrived example of how things can go wrong:

public class MyBasePanel extends JPanel {
    public MyBasePanel() {
        initializeComponents();
    }

    private void initializeComponents() {
        // layout setup omitted
        // overridable call
        add(new JLabel("My label"), BorderLayout.CENTER);
    }
}

public class MyDerivedPanel extends MyBasePanel {
    private final List<JLabel> addedLabels = new ArrayList<>();

    @Override
    public void add(Component comp, Object constraints) {
        super.add(comp);
        if (comp instanceof JLabel) {
            JLabel label = (JLabel) comp;
            addedLabels.add(label); // NPE here
        }
    }
}

推荐答案

为避免在构造函数中将Swing组件连接在一起,您可以简单地将连接的责任交给另一个对象.例如,您可以将接线职责交给工厂:

To avoid wiring Swing components together in the constructor, you could simply give the responsibility of the wiring to another object. For instance, you could give wiring duties to a Factory:

public class MyPanelFactory {
    public MyBasePanel myBasePanel() {
        MyBasePanel myBasePanel = new MyBasePanel();
        initMyBasePanel(myBasePanel);
        return myBasePanel;
    }

    public MyDerivedPanel myDerivedPanel() {
        MyDerivedPanel myDerivedPanel = new MyDerivedPanel();
        initMyBasePanel(myDerivedPanel);
        return myDerivedPanel;
    }

    private void initMyBasePanel(MyBasePanel myBasePanel) {
        myBasePanel.add(new JLabel("My label"), BorderLayout.CENTER);
    }
}

或者您可以全力以赴并使用依赖项注入容器实例化所有Swing组件,然后让该容器触发布线.这是Dagger的示例:

Or you could go all out and instantiate all your Swing components with a dependency injection container and have the container trigger the wiring. Here's an example with Dagger:

@Module
public class MyPanelModule {
    static class MyBasePanel extends JPanel {
        private final JLabel myLabel;

        MyBasePanel(JLabel myLabel) {
            this.myLabel = myLabel;
        }

        void initComponents() {
            this.add(myLabel, BorderLayout.CENTER);
        }
    }

    static class MyDerivedPanel extends MyBasePanel {
        private final List<JLabel> addedLabels = new ArrayList<>();

        MyDerivedPanel(JLabel myLabel) {
            super(myLabel);
        }

        @Override
        public void add(Component comp, Object constraints) {
            super.add(comp);
            if (comp instanceof JLabel) {
                JLabel label = (JLabel) comp;
                addedLabels.add(label);
            }
        }
    }

    @Provides MyBasePanel myBasePanel(@Named("myLabel") JLabel myLabel) {
        MyBasePanel myBasePanel = new MyBasePanel(myLabel);
        myBasePanel.initComponents();
        return myBasePanel;
    }

    @Provides MyDerivedPanel myDerivedPanel(@Named("myLabel") JLabel myLabel) {
        MyDerivedPanel myDerivedPanel = new MyDerivedPanel(myLabel);
        myDerivedPanel.initComponents();
        return myDerivedPanel;
    }

    @Provides @Named("myLabel") JLabel myLabel() {
        return new JLabel("My label");
    }
}

这篇关于在构造函数中调用诸如Swing的add()之类的可重写方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆