Search code examples
actionscriptdesign-patternscoupling

Flash / ActionScript - application design question


Could someone share the way how this should be designed:

Let's say I have some data model, which is built using Entries.

Basically, I have one abstract class Entry (or interface IEntry - that's not so important for the case) and have several implementations of this class - MovieEntry, SoundEntry, FoodEntry, whatever...

Each of those is a wrapper for some data (url, description, number of calories, etc) and this data is grouped together in each corresponding class.


Now - if I wish to display the data for the entries on the screen (let's say movie posters and annotations for the MovieEntry) - how should I design that?

Obviously I could provide another interface / abstract class and call it DrawableEntry (and it would inherit Sprite) and then build a bunch of classes like DrawableMovieEntry and DrawableSoundEntry which could look like:

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

   private movieEntry:MovieEntry;

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

But this seems to be kind of an overkill for a small application.

Another approach is to make the MovieEntry, SoundEntry, ... extend sprite and provide the drawing implementations themselves - but this is obviously bad, because data becomes strongly coupled with it's visualization routines.

So - how should this be done? Maybe MVC approach has something to offer for this case?


Solution

  • Your use case seems to be the perfect example for the Strategy pattern or the Command pattern.
    Strategy being the simpler one, here is an example:

    Create an IDrawStrategy interface like this:

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

    Implement several 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
        }
      }
    }
    

    etc.

    Then add a new member to your base Entry class:

    private var _drawStrategy:IDrawStrategy;
    

    and create a setter:

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

    and a draw method:

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

    You can now assign and execute the fitting strategies to each of your entries:

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

    BTW the Sprite you draw the information in can, but doesn't have to, be a member of the DrawStrategy class, but if you wanted to add a clear() method later, it would be better to keep a reference ;).