Flash / ActionScript - вопрос дизайна приложения - PullRequest
1 голос
/ 09 января 2011

Может кто-нибудь поделиться тем, как это должно быть разработано:

Допустим, у меня есть некоторая модель данных, построенная с использованием Entries.

По сути, у меня есть один абстрактный класс Entry (или интерфейс IEntry - это не так важно для данного случая), и у меня есть несколько реализаций этого класса - MovieEntry, SoundEntry, FoodEntry, что угодно. ..

Каждый из них является оберткой для некоторых данных (URL, описание, количество калорий и т. Д.), И эти данные сгруппированы в каждом соответствующем классе.


Теперь - если я хочу отобразить данные для записей на экране (скажем, постеры фильмов и аннотации для MovieEntry) - как мне это оформить?

Очевидно, я мог бы предоставить другой интерфейс / абстрактный класс и назвать его DrawableEntry (и он унаследовал бы Sprite) , а затем создать группу классов, таких как DrawableMovieEntry и DrawableSoundEntry, которые могли бы выглядеть так:

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, ... расширять спрайт и предоставлять сами реализации чертежей - но это, очевидно, плохо, поскольку данные сильно связаны с процедурами визуализации.

Итак, как это сделать? Может, у MVC-подхода есть что предложить для этого случая?

Ответы [ 2 ]

1 голос
/ 10 января 2011

Ваш вариант использования, кажется, является идеальным примером для шаблона стратегии или шаблона команды .
Стратегия является более простой, вот пример:

Создайте интерфейс 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;
}

и метод рисования:

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

Теперь вы можете назначать и выполнять стратегии подбора для каждого изВаши записи:

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

Кстати, Sprite, в котором вы рисуете информацию, может, но не обязан, быть членом класса DrawStrategy, но если вы захотите добавить метод clear () позже,было бы лучше сохранить ссылку;).

1 голос
/ 10 января 2011

Записи, с помощью которых вы строите модель данных, называются, среди прочего, объектами значений (VO) или объектами значений данных (DVO).Чтобы ответить на ваш последний вопрос в первую очередь, я бы никогда не предоставил бы VO-расширение, отличное от базового VO-класса, поэтому не расширяйте Sprite, вы пожалеете об этом позже.

Болеев иерархию.Вы расширяете абстрактный класс Entry для создания конкретных подклассов, но, поскольку вы также упоминаете возможный интерфейс, я не уверен, что вам следует использовать extension.Используйте общий базовый класс, только если ваши объекты-значения на самом деле имеют общие свойства.Если каждая запись имеет свойство title, хорошо, поместите это в Entry и сделайте его подклассом.Если ваш тезис будет пустым, я бы рекомендовал вместо этого использовать интерфейс маркера (= пусто).

У меня есть общий интерфейс маркера для объектов-значений, которые имеют более специфические подинтерфейсы для добавления таких функций, как синтаксический анализ или композиция xml.,Как только вы начнете использовать интерфейсы для этого, его легко улучшить.

Затем отображение.Там нет одного правильного ответа на этот, тем более, что ваш пример все еще довольно широк.Но я бы передал VO объекту в целом через метод, который заявляет, что он будет хранить VO и перерисовывать сам.

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

Используйте интерфейс IEntry для передачи объекта в целом.В вашей реализации используйте каскад if с условиями is Type для рисования.

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, используйте его вместо интерфейса.Вы хотите, чтобы ваши методы запрашивали тип объекта значения, который настолько близок к необходимому объекту, насколько это необходимо.

Поскольку вы сохраняете запись в своем классе отображения, через некоторое время ее легко передать, когда вы щелкнете по экрану.или когда вы хотите, чтобы он сделал что-то еще.

Помогает ли это?

...