【问题标题】:How to create an abstract class with static factory method?如何使用静态工厂方法创建抽象类?
【发布时间】:2016-08-21 12:18:57
【问题描述】:

我有一个“标准”JPanel,里面有两个面板。我试图创建一种模板类,然后扩展它并实现内容。问题是哪种方法可以实现它。

下面的代码是我试图让它工作的代码,但我刚刚开始阅读 Effective Java 书,我不熟悉静态工厂方法。特别想把它们抽象出来。

我特别想遵循的书中的一些提示是

  • 考虑静态工厂方法而不是构造函数
  • 优先组合优于继承
  • 首选接口而不是抽象类

但我找不到关于这些点的好的解决方案(没有它们:P)。

public abstract class CentralPage {

    static JPanel getInstance() {
        JPanel container = new JPanel();
        container.setBackground(Color.white);
        container.setBorder(
                BorderFactory.createCompoundBorder(new LineBorder(Color.BLACK), new EmptyBorder(10, 10, 10, 10)));
        container.setMinimumSize(new Dimension(960, 400));
        container.setPreferredSize(new Dimension(960, 400));
        container.setLayout(new BoxLayout(container, BoxLayout.Y_AXIS));

        JPanel up = getUp(container);
        container.add(up);
        JPanel down = getDown(container);
        container.add(down);
        return container;
    }

    abstract JPanel getDown(JPanel container);

    abstract JPanel getUp(JPanel container);

}

如果您需要有关代码其他部分的更多信息,请随时询问。

【问题讨论】:

  • 你想解决什么problem
  • 我想,我有一个带有默认静态工厂方法的抽象类,但不可能在抽象类上添加静态方法。所以我试图找到标准的解决方法。更好?
  • 提供静态工厂方法而不是构造函数的基本思想是隐藏实现。这些实现隐藏在私有或匿名类的某个地方。您的方法看起来更像抽象工厂方法。您应该提供一个通用的工厂界面,然后可以使用它来自定义您的面板。尽管如此,如果需要,您仍然可以将工厂方法的“默认”实现作为静态方法提供。
  • @kaetzacoatl 我想我不明白你的解决方案。如何提供带有接口的默认实现?请根据您的建议创建一个答案。

标签: java swing static-methods factory-pattern effective-java


【解决方案1】:

Java 静态方法不能是抽象的——讨论时间更长here

现在让我们分解你的构造:你的最终结果应该是一个有两个孩子的JPanel,也是JPanels,它自己的构造依赖于父JPanel。您希望在静态工厂方法中完成此构造。

如果这是正确的,这可能是一个解决方案:

public interface UpDown{
    public JPanel getUp(JPanel parent);
    public JPanel getDown(JPanel parent);
}

public class CentralPage{
    static JPanel getInstance(UpDown components){
        JPanel container = new JPanel();
        container.setBackground(Color.white);
        container.setBorder(
                BorderFactory.createCompoundBorder(new LineBorder(Color.BLACK), new EmptyBorder(10, 10, 10, 10)));
        container.setMinimumSize(new Dimension(960, 400));
        container.setPreferredSize(new Dimension(960, 400));
        container.setLayout(new BoxLayout(container, BoxLayout.Y_AXIS));

        JPanel up = components.getUp(container);
        container.add(up);
        JPanel down = components.getDown(container);
        container.add(down);
        return container;
    }
}

另一个更接近您原始提案的解决方案是这样的:

public abstract class CentralPage{

    private static CentralPage page;

    protected JPanel container;

    protected CentralPage(){
        container = new JPanel();
        container.setBackground(Color.white);
        container.setBorder(
               BorderFactory.createCompoundBorder(new LineBorder(Color.BLACK), new EmptyBorder(10, 10, 10, 10)));
        container.setMinimumSize(new Dimension(960, 400));
        container.setPreferredSize(new Dimension(960, 400));
        container.setLayout(new BoxLayout(container, BoxLayout.Y_AXIS));

        JPanel up = getUp(container);
        container.add(up);
        JPanel down = getDown(container);
        container.add(down);
    }

    static JPanel getInstance(){
        if(page==null){
            page=new CentralPage();
        }
        return page.getContainer();
    }

    abstract JPanel getDown(JPanel container);

    abstract JPanel getUp(JPanel container);

    protected JPanel getContainer(){
         return this.container;
    }
}

这种(相当反模式)方法的缺点是您需要记住在调用super() 的具体类上创建构造函数;

【讨论】:

  • 我应该如何在“子”类中“调用”它? (实现 UpDown 的类)static JPanel getInstance() { return CentralPage.getInstance(this); } ?
  • 这是不可能的,因为thisstatic 方法中没有任何意义。但是为什么要在子类中构造父类呢?您可能有更大的范围(例如您的 UI 应用程序),您可以在其中调用 JPanel mainPanel=CentralPage.getInstance(new UpDown(){/*implement the two methods*/});
【解决方案2】:

祝贺您阅读了“Effective Java”并尝试将其付诸实践。它将为您的代码带来更多的可用性和清晰性。

现在,让我们看看:

1.首先,如果你的抽象CentralPage在构造时只需要两个Panel对象,最简单的方法是构造函数中有两个参数的非抽象类

public class CentralPage
{
  public CentralPage(Panel up, Panel dn)
  {
      ...
  }
}

2.如果除了在构造时接收参数之外,还有一些CentralPage 不知道的行为,并且必须在对象生命周期内的任何时间(在构造函数结束后)委托给第三方,正确的模式应该是一个抽象类,每个需要的行为都有一个抽象方法

public abstract class CentralPage
{
  protected CentralPage(...)
  {
      ...
  }

  protected abstract return-type myBehaviour1(parameters...)
  {
      ...
  }

  protected abstract return-type myBehaviour2(parameters...)
  {
      ...
  }
}

而且,每个非抽象子类必须提供实现其相应方法所需的每个行为。

3.静态工厂方法是针对非抽象类的。它的目的是决定是否必须创建一个对象(也许可以重复使用现有的对象,就像在单例模式中一样),并最终决定必须实例化哪个类(可能是所有者类本身,也可能是某个子类)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-12
    • 2011-03-17
    • 2010-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-05
    相关资源
    最近更新 更多