【问题标题】:Referencing a java class in its own constructor在自己的构造函数中引用 java 类
【发布时间】:2018-10-19 14:07:49
【问题描述】:

我正在构建一个名为 ListView 的 Java Swing 类,它试图成为一个通用列表。

public class ListView<T> extends JPanel {
    private IListViewDataSource<T> dataSource;
    private JPanel list;

    public ListView(IListViewDataSource<T> dataSource, Dimension dimension) {
        this.dataSource = dataSource;

        list = new JPanel(new GridLayout(0, 1));
        this.add(new JScrollPane(list));


        this.setPreferredSize(dimension);
    }

    public void loadRows() {
        for (int i = 0; i < dataSource.getNumberOfElements(); i++) {
            JLabel label = new JLabel(dataSource.getTitleOfElement(dataSource.getElementAtPosition(i)));
            list.add(label);
        }
    }
}

为了做到这一点,我声明了一个名为 IListViewDataSource 的接口,它定义了列表视图获取其数据所需的方法。

public interface IListViewDataSource<T> {
    T getElementAtPosition(int position);
    int getNumberOfElements();
    String getTitleOfElement(T element);
}

我希望可以使用您声明的任何 DataSource 实例化一个新的 ListView,以便在列表中引入任何数据。到目前为止一切顺利。

现在,我正在构建另一个名为 OfferListView 的类,它扩展了 ListView,为了不产生不必要的额外文件,我希望它实现自己的 ListViewDataSource。问题是我不能在这个新类的构造函数中调用super(this, dimension),因为我被告知在调用超类构造函数之前不能使用this

这个“模式”是使用 iOS 的 UIKit 编程时使用的,我认为它非常好,但我无法让它在 Java 中工作。我该如何处理?

【问题讨论】:

  • 首先这不是模型视图控制器。其次,如果你想让你的领域层独立于视图,那么你可以使用观察者设计模式来做到这一点。
  • **EXTRA: ** 在这种编程中你不需要控制器,你可以直接引用域对象但让域对象触发事件。例如,查看PropertyChangeListener 的工作原理。在域中提供一个简单的订阅函数,注册所有实现PropertyChangeListener的元素
  • @LuaiGhunim 老实说,我对 java 设计模式缺乏经验,所以我不太明白你的建议。可以举个例子吗?
  • 从域中分离视图的例子?

标签: java swing model-view-controller constructor


【解决方案1】:

Domain-View-Controller 策略于 90 年代在 smaltalk 上用于将视图与域分离,并且仍在 Web 开发中使用。

如果不为视图等编写所有类,则有两种方法可以将视图与域分开。

(1st:) 当视图将某些内容传递给域对象时,它会保留polling 以检查任何其他更改。这意味着一旦视图对象(文本字段、框架或其他任何内容)将请求转发到域,它会在几秒或几分钟后继续检查是否有更改。但是这种方法并不好。

(2nd:) 观察者设计模式。当一件事发生变化时,它会自动通知所有听众。您的视图必须实现一个接口,并且域应该为实现该接口的所有对象提供订阅方法。这是一个示例,我没有编译它,但是它清楚地将viewdomain 分开。

public class View implements PropertyChangeListener {

    private DomainObject object;

    public View(DomainObject object) {
        assert(object != null);
        this.setObject(object);
    }

    public void enterText(String text) {
        this.getObject().update(text);
    }

    @Override
    public void propertyChange(PropertyChangeEvent evt) {
         if(evt.getPropertyName().equals("string_updated"))
             System.out.println("New value is " + evt.getNewValue());
    }

    public DomainObject getObject() {
        return object;
    }

    public void setObject(DomainObject object) {
        this.object = object;
    }

}

这是域类:

public class DomainObject {

    private String text;


    public DomainObject(String test) {
        this.setText(test);
    }


    public String getText() {
        return text;
    }
    public void setText(String text) {
        this.text = text;
    }

    public void update(String string) {
        this.setText(string);
        this.getListener().stream().forEach(e -> e.propertyChange(new PropertyChangeEvent(this,"string_updated","",this.getText())));
    }

    private ArrayList<PropertyChangeListener> listener;

    public void subscribe(PropertyChangeListener listener) {
        this.getListener().add(listener);
    }


    public ArrayList<PropertyChangeListener> getListener() {
        return listener;
    }


    public void setListener(ArrayList<PropertyChangeListener> listener) {
        this.listener = listener;
    }


}

如我所见,您试图拥有很多视图,如果它们包含在彼此之间,那么也使用 Composite design pattern

【讨论】:

  • 这都是为了更新列表元素,对吧?我只想为列表提供数据,以便我可以将 ListView 与不同的数据集重用
  • 当列表改变时会发生什么?它触发了一个被视图捕获的事件,它只是视图是否将其显示为机器人、机器或字符串!顺便说一句,在学习设计模式之前检查 9 GRASP 原则。
猜你喜欢
  • 2012-08-20
  • 2013-01-11
  • 1970-01-01
  • 2017-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-17
相关资源
最近更新 更多