オブザーバーパターンを使用した制御の反転をお勧めします
これが私の提案を説明するための作業セットアップです。私のコードでは、各ユニットはリソースを 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; }
}
すべてがうまくいくことを願っています。少しでも不明な点があればコメントを書いてください。