1

有人可以分享应该如何设计的方式:

假设我有一些数据模型,它是使用Entries.

基本上,我有一个抽象类Entry(或接口IEntry——这对这种情况来说并不那么重要),并且有这个类的几个实现—— MovieEntry、、、SoundEntry等等FoodEntry……

每一个都是一些数据(url、描述、卡路里数量等)的包装器,并且这些数据在每个相应的类中组合在一起。


现在 - 如果我希望在屏幕上显示条目的数据(比如说电影海报和注释MovieEntry) - 我应该如何设计呢?

显然,我可以提供另一个接口/抽象类并调用它DrawableEntry (它会继承Sprite,然后构建一堆类DrawableMovieEntryDrawableSoundEntry如下所示:

class DrawableMovieEntry extends DrawableEntry { // which also extends 'Sprite'

   private movieEntry:MovieEntry;

   public override function draw(backend:*) {
      // Draw everything using the 'movieEntry' reference
      // stored.
};

但这对于小型应用程序来说似乎有点过头了。

另一种方法是使MovieEntry, SoundEntry, ... 扩展 sprite 并自己提供绘图实现 - 但这显然很糟糕,因为数据与其可视化例程紧密耦合。

那么 - 这应该怎么做呢?也许 MVC 方法可以为这种情况提供一些东西?

4

2 回答 2

1

用于构建数据模型的条目被称为值对象 (VO) 或数据值对象 (DVO)。首先回答你的最后一个问题,我永远不会让 VO 扩展除了基本 VO 类之外的东西,所以不要扩展 Sprite,你以后会后悔的。

转到层次结构。您正在扩展抽象类Entry以创建具体的子类,但由于您还提到了一个可能的接口,我不确定您是否应该使用扩展。如果您的值对象实际上共享公共属性,则仅使用公共基类。如果每个条目都有一个title属性,很好,把那个放进去Entry并继承它。如果您的摘要为空,我建议您改用标记 (=empty) 接口。

我有一个用于值对象的通用标记接口,它具有更具体的子接口来添加诸如 xml 解析或组合之类的功能。一旦你开始为此使用接口,它就很容易增强。

然后是显示。这个问题没有一个正确的答案,更多的是因为你的例子仍然很广泛。但是我会将 VO 作为一个整体传递给对象,通过一个声明它将存储 VO 并重绘自身的方法。

interface IEntryDisplay {
    redrawWithEntry(entry:IEntry):void;
}

使用 IEntry 接口将对象作为一个整体传递。在您的实现中,使用带有is Type条件的 if 级联来进行绘图。

public function redrawWithEntry(entry:IEntry):void {
    this.entry = entry;

    if (entry is MovieEntry) {
        title.text = MovieEntry(entry).title;
    } else if (entry is SoundEntry) {
        title.text = "(Sound) "+SoundEntry(entry).fileName;
    }
}

如果您决定为 Entry 层次结构使用基类,请使用该基类而不是接口。您希望您的方法要求尽可能接近所需对象的值对象类型。

因为您将条目存储在您的显示类中,所以稍后当您单击显示或希望它执行其他操作时很容易传递。

这有帮助吗?

于 2011-01-09T22:23:45.190 回答
1

您的用例似乎是Strategy 模式Command 模式的完美示例。
策略比较简单,这里有一个例子:

像这样创建一个 IDrawStrategy 接口:

package {
  public interface IDrawStrategy {
    function draw( obj:Object ) : void;
  }
}

实现几个 DrawStrategies:

package {
  public class SoundEntryDrawStrategy implements IDrawStrategy {
    public function draw (obj:Object) : void {
       // cast obj to SoundEntry and do all the drawing necessary, 
       // or fail if obj is null or not a SoundEntry
    }
  }
}

package {
  public class MovieEntryDrawStrategy implements IDrawStrategy {
    public function draw (obj:Object) : void {
       // cast obj to MovieEntry and do all the drawing necessary
       // or fail if obj is null or not a MovieEntry
    }
  }
}

等等

然后将一个新成员添加到您的基本 Entry 类中:

private var _drawStrategy:IDrawStrategy;

并创建一个设置器:

public function set drawStrategy ( strat:IDrawStrategy ) : void {
    _drawStrategy = strat;
}

和一个draw方法:

public function draw () : void {
  _drawStrategy.draw( this );
}

您现在可以为每个条目分配和执行拟合策略:

var mov:MovieEntry = new MovieEntry();
mov.drawStrategy = new MovieEntryDrawStrategy();
mov.draw();

顺便说一句,您在其中绘制信息的 Sprite 可以(但不一定)是 DrawStrategy 类的成员,但是如果您以后想添加 clear() 方法,最好保留一个引用;)。

于 2011-01-10T10:38:01.310 回答