2008/08/13 | AS3 策略模式 的一个样例。
类别(Flash学习笔记) | 评论(1) | 阅读(609) | 发表于 22:00

  Head First 是本好书,虽然是以类 Java 语言来写的示例,但一点也不会妨碍AS程序员来阅读,终于粗略的过完了第一遍,现在进入精读了,手头刚好就有这么个任务,用多种形式播放声音波形,这是策略模式的一个典型应用。

  基础知识,位图的创建、加载滤镜,声音波谱数据的读取,相关见容请参考帮助文件。

  我们的目标,通过鼠标点击在各种显示形式间进行切换。不同的显示形式,可以用各自的函数来代表,算是不同的算法或是不同的行为(说到封装不同的算法,让我想起模板方法)。为了达到可以互换的效果,我们将每一种具体的显示形式独立出来,用一个个的类来实现。为了让这些各自独立的显示效果有一个统一的规范,我们定义一个接口标准,在这里称为ISoundStyle,我们通过继承这个接口,并且重写相关函数,得到3个显示效果类,分别是 LineStyle CircleStyle 和DoubleCircleStyle,我们的主类是 SndSpectrum 类,它是做为文档类来用的。文档类的代码如下:

package {
 import flash.display.Sprite;
 import flash.display.Bitmap;
 import flash.display.BitmapData;

 import flash.events.Event;
 import flash.events.MouseEvent;

 //import flash.geom.Matrix;
 import flash.geom.Point;

 import flash.filters.BlurFilter;
 import flash.filters.ColorMatrixFilter;

 import flash.net.URLRequest;

 import flash.media.Sound;
 import flash.utils.ByteArray;
 import flash.media.SoundMixer;

 import ISondStyle;
 import LineStyle;
 import CircleStyle;
 import DoubleCircleStyle;

 public class SndSpectrum extends Sprite {

  public var s:Sound;
  public var ba:ByteArray;
  public var bmd:BitmapData;
  public var bm:Bitmap;
  public var sp:Sprite;

  public var style:ISoundStyle = new LineStyle();

  public function SndSpectrum() {
   sp = new Sprite();
   addChild(sp);

   ba = new ByteArray();
   bmd = new BitmapData(stage.stageWidth, stage.stageHeight, true, 0x000000);
   bm = new Bitmap(bmd);
   addChild(bm);

   s = new Sound(new URLRequest("song.mp3"));
   s.play(0, 1000);

   addEventListener(Event.ENTER_FRAME, loop);
   stage.addEventListener(MouseEvent.CLICK, onClick);
  }

  private var blur:BlurFilter = new BlurFilter(10,10,3);

  private var colorMatrix:ColorMatrixFilter = new ColorMatrixFilter([
  1, 0, 0, 0, 0,
       0, 1, 0, 0, 0,
       0, 0, 2, 0, 0,
       0, 0, 0, 1, 0
  ]);

  public function loop(e:Event):void {
   sp.graphics.clear();
   sp.graphics.lineStyle(3, 0xFFFFFF);
   sp.graphics.moveTo(-1, 150);
   SoundMixer.computeSpectrum(ba);

   style.showStyle( ba,sp );

   bmd.draw(sp);
   bmd.applyFilter(bmd,bmd.rect,new Point(),blur);
   bmd.applyFilter(bmd,bmd.rect,new Point(),colorMatrix);
   bmd.scroll(3,0);
  }
  public var count:int = 1;// 在各种效果间切换 统计
  public function onClick(evt:MouseEvent) {
   switch ( count ) {
    case 1 :
     style = new CircleStyle();
     count++;
     break;
    case 2 :
     style = new DoubleCircleStyle();
     count++;
     break;
    case 3 :
     style = new LineStyle();
     count = 1;
     break;
   }
  }
 }
}

上面红色的两行代码,是策略模式的关键,主类中以接口类为属性,在需要的地方实例化不同的行为。不同行为之间的切换,我用了一个变量来代表,每一次切换该变量值会发生改变,在下次显示不同的效果,这个变量可以考虑放到接口中去,用一个代理类的 showNextStyle 方法来管理这些效果切换,可能会更好一些,如此一来,似乎又和工厂模式扯上关系了,先不管这么多了,暂且按策略模式来计论吧。

完成的效果如下,点击flash窗口,可以实现效果切换:

源代码下载:

 压缩包下载

第一种圆环内同时显示着左右声道,第二种双环,将左右声道分开来显示,在音乐中,经常会看到蝴蝶飞舞的身影,这难道就是一次艺术的巧合?

这里还存在问题,如果 sp 对象中需要一些更复杂的显示效果,比如让首次出现的直线进行旋转,需要借助下一层的对象来实现,现有的结构中没有足够的控制能力,那么增加一个代理,或者称为一个工厂或许更合适一些。下次讨论一下。

3

评论Comments