1

血流をモデル化しようとしています。それが得られるのと同じくらい簡単に、イベント(TimerTick)がユニットAからユニットBへ、BからCへ、CからAへのリソースオブジェクトの転送をトリガーしようとしています。ある反復から別の反復まで、以下に貼り付けたものよりもはるかに多くの異なる方法を試しました. ユニットは、構築後に三角形として接続されます。これにより最初のユニットが誤ったままになることは承知しており、それに対処するためにさまざまな方法を試しましたが (それが唯一の問題かどうかはわかりません)、どれもうまくいかなかったので投稿しません。1 つのユニットが他のユニットについて知る必要のないイベント設定のアイデアは、非常に高く評価されます。しかし、これを機能させる方法も高く評価されます。

class Unit{    
Resource currentResource;
Resource incomingResource;
Unit preUnit;
Unit postUnit;
public Unit( int resource, Timer t)
    {
        this.currentResource = new Resource(resource);
        t.TimerTick += T_TimerTick;
    }
 private void T_TimerTick(object sender, TimerTickEventArgs e)
    {
        postUnit.receiveResource(currentResource);
        currentResource = incomingResource;
}
void receiveResource(Resource resource)
    {
        incomingResource = resource;
    }
//pre and post units connected appropriately to Cycle ...-A-B-C-A-...
// with one cycle per TimerTick
}
4

2 に答える 2

0

オブザーバーパターンを使用した制御の反転をお勧めします

これが私の提案を説明するための作業セットアップです。私のコードでは、各ユニットはリソースを 1 だけインクリメントします。

そして、次の出力を生成します

*開始ユニット A 値 1

ユニットA、出力1

ユニット B、入力 1

ユニットB、出力2

ユニット C、入力 2

ユニット C、出力 3

ユニット A、入力 3

ユニット A、サイクル完了*

クライアントコード

      IInitiatorUnit A = new InitiatorUnit("A");
        IUnit B = new Unit("B");
        IUnit C = new Unit("C");

        B.RegisterUnit(A); // B is listening to A
        C.RegisterUnit(B); // C is listening to B
        A.RegisterUnit(C); //  A is listinig to C


 void heartBeatTimer_Tick(object sender, EventArgs e)
    {
        A.GenerateResource(1); // Start the process
    }

入力を受け取り、それを処理し、イベントを発生させるようにユニットを設計しました

     interface IUnit
    {
        event EventHandler<ResourceGeneratedEventArgs> ResourceGenerated;
        void RegisterUnit(IUnit inputUnit);
        string Name { get; }
    }

    class Unit : IUnit
    {

        IUnit mInputUnit;
        public event EventHandler<ResourceGeneratedEventArgs> ResourceGenerated;
        public string Name { get; private set; }

        public Unit(string name)
        {
            this.Name = name;
        }

        public void RegisterUnit(IUnit inputUnit)
        {
            this.mInputUnit = inputUnit;
            this.mInputUnit.ResourceGenerated += mInputUnitResourceGenrated;
        }

        void mInputUnitResourceGenrated(object sender, ResourceGeneratedEventArgs inputResource)
        {
           //take the input resorce. pocess it & fire the event;
            //I'm just adding 1 to it as sample

            int outputResource = inputResource.Resource + 1;

            Console.WriteLine("Unit {0}, input {1} ", this.Name, inputResource.Resource, outputResource);

            OnResourceGenerated(outputResource);
        }      

        protected virtual void OnResourceGenerated(int outputResource)
        {
            Console.WriteLine("Unit {0}, output {1}", this.Name,  outputResource);

             if (ResourceGenerated != null)
                ResourceGenerated(this, new ResourceGeneratedEventArgs(outputResource));
        }
    }


    public class ResourceGeneratedEventArgs : EventArgs
    {
        public ResourceGeneratedEventArgs(int resource)
        {
            Resource = resource;
        }

        public int Resource { get; private set; }
    } 



     /// <summary>
     /// This is just to start the process here, Nothing great here 
     /// </summary>
     interface IInitiatorUnit : IUnit
     {
        void  GenerateResource(int initialValue);
     }


    class InitiatorUnit : Unit, IInitiatorUnit
    {
        //prevents the cycle from going on & on
        bool resetFlag;

        public InitiatorUnit(string name):base(name)
        {

        }

        public void GenerateResource(int initialValue)
        {
            resetFlag = false;
            Console.WriteLine("Initiating Unit {0} value {1}", this.Name, initialValue);
            OnResourceGenerated(initialValue);
        }

        protected override void OnResourceGenerated(int outputResource)
        {
            //Dont raise the event. if the cycle has completed
            if (resetFlag == false)
            {
                resetFlag = true;
                base.OnResourceGenerated(outputResource);
            }
            else
            {
                //do nothing, cycle has completed
                Console.WriteLine("Unit {0}, Cycle complete", this.Name);
            }
        }
    }

編集1:非常に多数のユニットへのアプローチ

私の最初のアプローチでは、各ユニットが後続のユニットを呼び出して、次のようなチェーンを作成しました-ここに画像の説明を入力

ノードが増えると、コール スタックの深さも増えるため、数が数千に達すると、スタック リミットを超えてスタック オーバー フローが発生する可能性があります。

したがって、新しいアプローチは、ユニットを反復処理するだけで、各ユニットにリクエストを与え、レスポンスを取得し、リクエストとして後続のユニットにレスポンスをフィードします。このようなもの -

ここに画像の説明を入力

これは実際のサンプルであり、次の出力が生成されます-

ユニット A、入力 0 ユニット A、出力 1 ユニット B、入力 1 ユニット B、出力 2 ユニット C、入力 2 ユニット C、出力 3 サイクル完了結果 3

クライアントコード

private void ClientCode()
    {
        // Create an array of units 
        IUnit[] units = new IUnit[] {
            new Unit("A"), // A will be called 1st . It needs to be given an initial value to start processing
            new Unit("B"), // B will get A's Output to process. 
            new Unit("C"), // C will get B's Output to process. 
        };

        // pass the array to workflow to process 
        cycle = new WorkFlow(units);

        Console.ReadLine();
    }

心拍タイマー

  void heartBeatTimer_Tick(object sender, EventArgs e)
    {
        var result = cycle.Execute(new Resource(0)); // starting the cycle with initial value of 0

        Console.WriteLine("Cycle completed result {0}", result.Value); 
    }

インフラストラクチャははるかにシンプルになり、

    interface IUnit
    {
        Resource ProcessResource(Resource inputResource);
        string Name { get; }
    }

    class Unit : IUnit
    {
        public string Name { get; private set; }

        public Unit(string name)
        {
            this.Name = name;
        }

        public Resource ProcessResource(Resource inputResource)
        {
            //take the input resorce. pocess it & fire the event;
            //I'm just adding 1 to it as sample

            int outputResource = inputResource.Value + 1;

            Console.WriteLine("Unit {0}, input {1} ", this.Name, inputResource.Value);
            Console.WriteLine("Unit {0}, output {1} ", this.Name, outputResource);


            return new Resource(outputResource);
        }
    }


    class WorkFlow
    {
        IUnit[] mUnits;

        public WorkFlow(IUnit[] units)
        {
            this.mUnits = units;
        }

        public Resource Execute(Resource initiatingResource)
        {
            Resource result = initiatingResource; // initialise result with the input of the cycle.
            for (int i = 0; i < mUnits.Length; i++)
            {
                // the result is passed as input. 
                //IUnit.ProcessResource function gives back a new result which is encached as input for subsequent resource
                result = mUnits[i].ProcessResource(result);
            }
            return result; // after all are processed, 
        }
    }

    public class Resource
    {
        public Resource(int resourceValue)
        {
            Value = resourceValue;
        }

        public int Value { get; private set; }
    }  

すべてがうまくいくことを願っています。少しでも不明な点があればコメントを書いてください。

于 2015-10-24T08:33:14.817 に答える