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