2016年1月11日月曜日

[C#]MVCフレームワークのController

オープンソースなIoT向けフレームワークの公開に向けて情報整理。
プログラムで一番やっかいなものといえば、「バグ」である。

排除するのはとても難しい。

人によって書き方が変わるし、バグが混入する箇所も様々あるが、フレームワークの規定で書き方を統一することで自由度を減らす代わりバグ混入を制限することができる。
Modelは過去に書いたので今回はController部分。


WEBアプリの場合は、ゲームでいうところターン制のようなもので、

1リクエストのレスポンス(結果)を返し、ステップアップ方式でページを遷移させて目的の結果を表示する、

というのが1つの戦略になると思う。


IoTの場合はリアルタイムに変わっていくので、常時状態を監視しなくてはならない。

例えば料理で目玉焼きを作るとき。

 ・フライパンの温度はどれくらいか?
 ・温まったらベーコンと卵を入れる
 ・おおよそ何分くらいになったらお皿に移す

というようなレシピがあったとしよう。

人によって毎回同じのものができるかといったらできないと思う。
その原因は毎回条件が変わっているから同じものができないということになる。


これをプログラムするのには、大体3つの要素

 状態をチェックする、イベントを起こす、行動に移す

あれば事足りるんじゃないかって言うことで試しに実装してみた。



using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
using System.Collections;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            var sec = new section1();
        }
    }

    /// 
    /// 状態リスト
    ///  セクション内にある状態一覧
    /// 
    public class StateList : Dictionary>
    {
        List states { get; } = new List();
        public bool Contains(object obj) => states.Contains(obj);

        public void Update()
        {
            states.Clear();
            states.AddRange(this.Where(_ => _.Value()).Select(_ => _.Key).ToArray());
        }
    }

    /// 
    /// アクションリスト
    ///  セクション内にあるアクション一覧
    /// 
    public class ActionList
    {
        List> actionList { get; } = new List>();
        List actions { get; } = new List();
        public bool Contains(Type type) => null != actions.Where(_=>_.GetType() == type).FirstOrDefault();

        public void Update()
        {
            var acts = actionList.Select(_ => _()).Where(_ => null != _).Where(_ => !Contains(_.GetType())).ToArray();
            actions.AddRange(acts);
        }

        public void Dispatch(StateList states, EventList events)
        {
            var next = actions.Where(_ => _.Dispatch()).ToArray();
            actions.Clear();
            actions.AddRange(next);
        }

        public void Add(Func action)
        {
            actionList.Add(action);
        }
    }

    /// 
    /// イベントリスト
    ///  セクション内にあるイベント一覧
    /// 
    public class EventList
    {
        Dictionary> eventList { get; } = new Dictionary>();
        List events { get; } = new List();
        public Func this[object key]
        {
            set
            {
                eventList[key] = value;
            }
        }

        public void Update(StateList states)
        {
            var evts = eventList.Where(_ => _.Value()).Select(_ => _.Key);
            foreach (var evt in evts)
            {
                if (!events.Contains(evt))
                {
                    events.Add(evt);
                }
            }
        }

        public bool Check(object evt)
        {
            if (events.Contains(evt))
            {
                events.Remove(evt);
                return true;
            }
            return false;
        }

        public void ResetAll()
        {
            events.Clear();
        }

    }

    /// 
    /// シーケンス処理
    ///  手続き型のバッチ処理
    /// 
    public class Sequence
    {
        protected delegate dlgStep dlgStep();
        protected dlgStep Current { get; set; }

        public bool Dispatch()
        {
            Current = Current();
            return null != Current;
        }
    }


    /// 
    /// セクション
    ///  作業領域の中にある一部ワークフロー
    /// 
    public class Section
    {
        public bool IsPower { get; set; } = true;
        public bool IsPause { get; private set; } = false;

        protected StateList States { get; } = new StateList();
        protected EventList Events { get; } = new EventList();
        protected ActionList Actions { get; } = new ActionList();
        Task task { get; set; }

        public void Start()
        {
            task = Task.Run((Action)TaskMain);
        }

        void TaskMain()
        {
            while (IsPower)
            {
                States.Update();
                Events.Update(States);
                Actions.Update();
                Actions.Dispatch(States, Events);
                Thread.Sleep(1);
            }
        }

        public void Pause() => IsPause = true;
        public void Resume() => IsPause = false;
        public void Stop() => IsPower = false;
    }


    public class section1 : Section
    {
        public object Context { get; set; }

        public section1()
        {
            States[Door.On] = () => true;
            //States[Door.Off] = null;
            //States[Switch.On] = null;
            //States[Switch.Off] = null;
            Events["event1"] = () => true;
            //Events["event2"] = () => false;
            //Events["event3"] = () => false;
            Actions.Add(Action1);
            //Actions.Add(Action2);
            //Actions.Add(Action3);
            Start();
        }

        Sequence Action1()
        {
            if(Events.Check("event1"))
            {
                return new DoorOpen(1);
            }
            return null;
        }

        //Sequence Action2()
        //{
        //    return null;
        //}

        //Sequence Action3()
        //{
        //    return null;
        //}

        enum Door { On, Off }
        enum Switch { On, Off }
    }

    public class DoorOpen : Sequence
    {
        object Arguments { get; }

        public DoorOpen(object arguments)
        {
            Current = Step1;
            Arguments = arguments;
            Console.WriteLine("init");
        }

        dlgStep Step1()
        {
            Console.WriteLine("1");
            return Step2;
        }

        dlgStep Step2()
        {
            Console.WriteLine("2");
            return Step3;
        }

        dlgStep Step3()
        {
            Console.WriteLine("3");
            return null;
        }
    }
}


{状態・イベント・アクション}これをセクション別に分けて置くことで
同じ状態でも異なったイベントやアクションを起こすことが可能になるというのが確認できたところで次回へ続く。


コメントを投稿

Androider