通用化UI组件

时间:2010-02-04 05:39:32

标签: java generics user-interface components fluent-interface

我几天都想弄清楚是否有可能,但我失败了,但也许有可能(我认为应该可行)。

假设我们有一些类似于Swing层次结构的UI组件+我们将使用流畅的接口Fluent Interfaces

public abstract class Component {

     ...

     public abstract Component setName(String name);

     public abstract String getName();

     ...

}

public abstract class Panel extends Component {
     ....
}

public abstract class TitledPanel extends Panel {
     ....

     public abstract TitledPanel setTitle(String title);

     public abstract String getTitle();
} 

是否可以使用泛型来编写类似的内容?

new TitledPanel().setName("panel").setTitle("Title);

setName应返回TitledPanel而不是Component,以便能够链接这些调用。

这只是一个简单的例子,但我的想法是,一旦我有一个类型为T的对象,任何调用超类的任何流体方法都会返回类型T.

编辑1:我忘了通过覆盖方法排除部分并返回协变类型:)我想要简单的泛型,如果可能的话。

3 个答案:

答案 0 :(得分:2)

首先,我建议只使用set方法,然后删除该设置。

您可以使用协变返回类型,但这意味着覆盖每个派生类中的每个方法。但是,它确实涉及很多非常繁琐的代码。

public abstract class Component {
    ...
    public Component name(String name) {
        this.name = name;
        return this
    }
}

public abstract class Panel extends Component {
    ...
    public Panel name(String name) {
        super.name(name);
        return this;
    }
}

添加通用THIS参数(作为枚举)使实现更容易,但客户端代码可能需要在声明中添加<?>

public abstract class Component<THIS extends Component<THIS>> {
    ...
    protected abstract THIS getThis();
    ...
    public THIS name(String name) {
        this.name = name;
        return this
    }
}

public abstract class Panel<THIS extends Panel<THIS>> extends Component<THIS> {
    ...
}

public class TitledPanel extends Panel<TitledPanel> {
    ...
    public TitledPanel getThis() {
        return this;
    }
}

另一种方法是使用Double Brace Idiom。

new TitledPane() {{
    name("panel");
    title("Title");
}}

答案 1 :(得分:1)

我不确定你是否可以通过泛型实现这一目标。你能做的就是这样:

public abstract class Component {

private String name;

public Component setName(String name) {
    this.name = name;
    return this;
}

public String getName() {
    return name;
}

}

public abstract class Panel extends Component {

}

public class TitledPanel extends Panel {

private String title;

public TitledPanel setTitle(String title) {
    this.title = title;
    return this;
}

@Override
public TitledPanel setName(String name) {
    super.setName(name);
    return this;
}

public String getTitle() {
    return title;
}

}

现在new TitledPanel().setName("panel").setTitle("Title");可以使用

答案 2 :(得分:1)

在你的TiltedPanel中(顺便说一句,如果你想要新的那个,那就不能抽象),你可以覆盖Component中的抽象方法并更改返回类型。返回类型不是方法签名的一部分,因此您可以使用不同的返回类型实现它:

public class Test
{
    public static void main(String[] args)
    {
        TiltedPanel p = new TiltedPanel().setName("panel").setTitle("title");
        System.out.println("name = " + p.getName());
        System.out.println("title = " + p.getTitle());
    }
}

abstract class Component
{
    public abstract Component setName(String name);

    public abstract String getName();
}

abstract class Panel extends Component
{
}

class TiltedPanel extends Panel
{
    private String title;
    private String name;

    public TiltedPanel setName(String name)
    {
        this.name = name;
        return this;
    }

    public String getName()
    {
        return this.name;
    }

    public TiltedPanel setTitle(String title)
    {
        this.title = title;
        return this;
    }

    public String getTitle()
    {
        return this.title;
    }
}