【问题标题】:GUI Pattern Question: PropertyChangeListener vs. Specialized View InterfaceGUI 模式问题:PropertyChangeListener 与专用视图接口
【发布时间】:2009-04-11 14:32:50
【问题描述】:

我想通过界面将模型与它的视图配对。我想控制视图更新的时间和频率。所以像 PropertyChangeListener 这样的东西不能很好地工作(在设置每个属性后触发一个事件)。

我不是为特定的 GUI 框架开发的。这里的目标是能够交换不同的 GUI 前端(现在用于测试,但以后可能对不同版本的应用程序有用)。这些可能是 Swing,也可能是 Web 浏览器(例如,通过 GWT)。

以下是我的方法。视图实现了一个接口来提供更新的方法。这由控制器在确定模型更新完成时触发。这对我来说仍然没问题,因为控制器只是通过模型与视图交互,控制器不依赖于视图的特定实现。

所以,我想我的问题是

  • 这行得通吗?
  • 这是标准做法吗?
  • 这个模式有名字吗?

粗略的代码示例(Java):

// Controller, manages Items (the model)
class ItemList {

   void addItem(Item item) {
   }

   void doStuffWithItems() {

     // perform some set of operations, such as sorting or layout
     for (Item item : items) {
       // ....
     }

     // now with everything in it's final position:
     for (Item item : items) {
       item.updateView();
     }
   }
}

// Model
class Item {
  private int top;
  private int left;
  private int width;
  private int height;

  // Can remember it's previous position/size:
  public void savePostion() {
  }

  // And recall it for the Controller to use:
  public public Position getSavedPosition() {
  }

  // Plus some other useful functions:
  public boolean intersectsWith(Item other) {

  }

  public void updateView() {
    this.view.update();
  }

  void setView(ItemView view) {
    this.view = view;
  } 
}

// Interface used by View implementations
public interface ItemView {
  // Trigger the view to reflect the current state of the model
  void update();
}

// Example, as a Swing component
class ItemComponent extends JComponent implements ItemView {
  private Item item;

  public ItemComponent(Item item) {
    this.item = item;
    item.setView(this);
  }

  // ItemView#update
  public void update() {
    // update the component's size/position
    setBounds(new Rectangle(item.getLeft(), item.getTop(), item.getWidth(), item.getHeight()));
  }

  @Override
  public void paint(Graphics g) {
    // ...
  }
}

【问题讨论】:

    标签: user-interface language-agnostic design-patterns


    【解决方案1】:

    我会避免强制视图实现一个仅用于更改通知的接口。而是在模型上创建一个单独的“立即更新”事件。

    【讨论】:

      【解决方案2】:

      模型不应直接控制或了解视图。视图应该向控制器注册一个回调,以便控制器可以告诉视图何时更新,这就是它的控制器的原因。您可以让模型允许 modelChangedEvent 的外部侦听器。然后视图可以在这方面向模型注册,而模型不知​​道有视图。请参阅 J2EE blueprint 了解 MVC 以及模型中状态更改的间接事件通知。

      【讨论】:

        【解决方案3】:

        对于在计算机桌面上运行的传统应用程序,我推荐Passive View 的变体。负责创建和管理表单的类是一个将事件传递给 UI 对象的瘦壳。 UI_Object 通过接口与表单交互。用术语来说,UI 对象实现了一个 UI_View 接口并将自己注册到位于对象层次结构中较低的视图控制器。

        UI_Object 然后执行对象,实现修改模型的Command Pattern。命令对象可以通过视图控件暴露的接口与各种视图交互。

        这样做的目的是允许您删除表单类并将它们替换为实现表单接口的存根类。存根类用于自动化测试,尤其是集成测试。

        接口精确地定义了表单、UI_Object、命令和视图之间的交互。它们可以设计为与语言无关,因此可以更轻松地在平台之间进行移植。

        您的示例中缺少的是命令对象。你需要这个结构

        • ItemViewForms
        • ItemView 实现
        • ItemViewForm界面
        • ItemViewCommands
        • 项目视图界面
        • 我的模特

        在ItemViewImplementation中加入ItemList

        ItemComponent 将使用 ItemViewInterface 向 ItemViewImplementation 注册。

        事件的顺序看起来像这样

        • 用户想要更新项目
        • 点击 UI(假设 UI 包括用鼠标点击)
        • 表格告诉 通过 ItemView 实现 X 的 ItemViewInterface 使用 Y 参数完成。
        • ItemView 实现然后 创建一个命令对象 它需要来自 Y 的参数。
        • 命令对象采用 Y 参数修改模型和 然后告诉
        • ItemView 实现通过 用于更新 UI 的 ItemViewInterface。
        • ItemViewImplementation 告诉 更新 UI 的 ItemViewForms 通过 ItemViewFormInterface。
        • ItemViewForms 更新。

        这种方法的优点是每一层的交互都是通过接口精确定义的。软件操作被本地化为命令对象。表单层专注于显示结果。 View 层负责在 Commands 和 Forms 之间路由动作和响应。命令是唯一修改模型的东西。此外,您还可以利用表单实现来替换您想要的任何 UI,包括用于单元测试的模拟对象。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-08-03
          • 2011-06-29
          • 2018-06-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-11-29
          相关资源
          最近更新 更多