2013-05-20

ActionScript3.0でinterfaceとDesignPatternを学習

ActionScript3 interface designpattern ActionScript3.0でinterfaceとDesignPatternを学習

状態遷移について調べた。状態遷移のことを英語では State transition というようだが、GoFデザインパターンのStateパターンを状態遷移に使えそうだ。

interface .. implements は、 extends .. override と似てる。「override」キーワードは いらないとこが違うくらいかな,文法的な違いは。

State Pattern

ソースは http://feb19.jp/blog/archives/000218.php をそのままコピーさせていただいた。ただし小さなクラスが複数ファイルになるとファイル開いたりが面倒なので、1ファイルにまとめている。

package 
{
    import flash.display.Sprite;
    import flash.events.Event;
    
    /**
     * ...
     * @author itouhiro
     */
    public class Main extends Sprite 
    {
        
        public function Main():void 
        {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }
        
        private function init(e:Event = null):void 
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            // entry point
            
            var context:Context = new Context();
            
            context.state = new StatePoor();
            context.request();
            
            context.state = new StateRich();
            context.request();
            
            context.state = new StateIkemen();
            context.request();
        }
    }
}

    interface IState {
        function handle():void;
        function giveName():void;
    }
    
    class Context {
        private var _state:IState;
        
        public function get state():IState
        {
            return _state;
        }
        public function set state(value:IState):void 
        {
            _state = value;
        }
        public function request():void 
        {
            state.giveName();
            trace('Marry me?');
            state.handle();
        }
    }
    
    class StatePoor implements IState {
        public function giveName():void {
            trace('\nPoor:');
        }
        public function handle():void {
            trace('NO');
        }
    }
    
    class StateRich implements IState {
        public function giveName():void {
            trace('\nRich:');
        }
        public function handle():void {
            trace('Yes');
        }
    }
    
    class StateIkemen implements IState {
        public function giveName():void {
            trace('\nIkemen:');
        }
        public function handle():void {
            trace('Yes! Yes!');
        }
    }

なるほど、IState型の変数(property)に、IStateをimplementsしたクラスを格納できるのか。そして、状態ごとのclassを作る‥‥。

interface使っているほかのデザインパターンも学習。

Strategy Pattern

http://feb19.jp/blog/archives/000209.php をそのままコピペさせていただいた。

Main.as

package 
{
    import flash.display.Sprite;
    import flash.events.Event;
    
    /**
     * ...
     * @author ..
     */
    public class Main extends Sprite 
    {
        
        public function Main():void 
        {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }
        
        private function init(e:Event = null):void 
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            // entry point
            
            trace('試合の経過');
            var plan:Plan;
            for (var i:int = 0; i < 5; i++) {
                if (Math.random() > 0.5) {
                    trace('\n優勢:');
                    plan = new Plan(new PlanLead());
                }else {
                    trace('\n劣勢:');
                    plan = new Plan(new PlanBehind());
                }
                plan.execute();
            }
        }
    }
}

    interface IStrategy {
        function execute():void;
    }
    
    class Plan {
        private var _strategy:IStrategy;
        public function Plan(strat:IStrategy) {
            _strategy = strat;
        }
        public function execute():void {
            _strategy.execute();
        }
    }
    class PlanLead implements IStrategy {
        public function execute():void {
            trace('手堅く守りを固めろ。');
        }
    }
    class PlanBehind implements IStrategy {
        public function execute():void {
            trace('強気で攻めるぜ!');
        }
    }

これはIStrategyが引数になるのか。

Command pattern

http://feb19.jp/blog/archives/000221.php をそのままコピペさせていただいた。

Main.as

package 
{
    import flash.display.Sprite;
    import flash.events.Event;
    
    /**
     * ...
     * @author itouhiro
     */
    public class Main extends Sprite 
    {
        
        public function Main():void 
        {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }
        
        private function init(e:Event = null):void 
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            // entry point
            
            var 計算者:操作者 = new 操作者();
            計算者.compute('+', 100);
            計算者.compute('-', 30);
            計算者.compute('*', 50);
            計算者.compute('/', 4);

            計算者.undo(4);
            
            計算者.redo(3);
        }
    }
}

    class Command {
        public function Command():void { }
        public function execute():void { }
        public function unexecute():void { }
    }
    class 計算 {
        private var c:int; //current
        public function operate(operator:String, operand:int):void {
            switch (operator) {
            case '+':
                c += operand;
                break;
            case '-':
                c -= operand;
                break;
            case '*':
                c *= operand;
                break;
            case '/':
                c /= operand;
                break;
            }
            trace('value=' + c +' (' + operator +' ' + operand +')');
        }
    }
    class 操作者 {
        private var cal:計算;
        private var cmds:Array;
        private var cur:int;
        
        public function 操作者() {
            cal = new 計算(); //calculator
            cmds = []; //commands
            cur = 0;   //current
        }
        public function redo(level:int):void {
            trace('.. redo ' + level +' times');
            for (var i:int = 0; i < level; i++) {
                if (cur < cmds.length - 1) {
                    var cmd:Command = cmds[cur++];
                    cmd.execute();
                }
            }
        }
        public function undo(level:int):void {
            trace('.. undo ' + level + ' times');
            for (var i:int = 0; i < level; i++) {
                if (cur > 0) {
                    var cmd:Command = cmds[--cur] as Command;
                    cmd.unexecute();
                }
            }
        }
        public function compute(operator:String, operand:int):void {
            var cmd:Command = new 計算命令(cal, operator, operand);
            cmd.execute();
            
            cmds.push(cmd);
            cur++;
        }
    }
    class 計算命令 extends Command {
        private var cal:計算;
        private var opt:String; //operator
        private var opd:int; //operand
        public function 計算命令(calculator:計算, operator:String, operand:int)
        {
            cal = calculator;
            opt = operator;
            opd = operand;
        }
        public function set operator(value:String):void {
            opt = value;
        }
        public function set operand(value:int):void {
            opd = value;
        }
        override public function execute():void {
            cal.operate(opt, opd);
        }
        override public function unexecute():void {
            cal.operate(undo(opt), opd);
        }
        private function undo(value:String):String {
            switch (value) {
            case '+': return '-';
            case '-': return '+';
            case '*': return '/';
            case '/': return '*';
            default:
                throw ArgumentError('演算子エラー:' + value);
            }
        }
    }

これは少し使うのが難しいかも‥これinterface使ってなかった。

0 件のコメント:

コメントを投稿

人気記事