Per prima cosa, lasciami dire che davvero non vedo un motivo per cui SuperCommand dovrebbe implementare l'interfaccia ICommand. A meno che non faccia parte di un quadro più ampio che non è menzionato in questa domanda, è assolutamente inutile. SuperCommand qui serve puramente come un wrapper attorno a diverse classi di comando eseguite.
Successivamente, ciò che @Neil ha descritto è molto, molto simile alla Catena di responsabilità modello di progettazione. Ciò significa che dovresti implementare CommandA, CommandB, CommandC in modo tale che i loro metodi Execute
vengano eseguiti solo per i tipi di dati corretti che vengono inviati a loro. In questo modo, puoi concatenare i comandi e lasciare che si preoccupino se qualcosa debba essere eseguito o meno. SuperCommand sarebbe solo un wrapper e un host per le tue classi di comando. Qualcosa del genere:
public class LegacyData
{
public string Type;
}
public abstract class Command
{
protected abstract bool DataCheck(LegacyData data);
public abstract void Execute(LegacyData data);
public Command Next { protected get; set; }
}
class CommandA : Command
{
protected override bool DataCheck(LegacyData data)
{
return data.Type == "A";
}
public override void Execute(LegacyData data)
{
if (DataCheck(data))
{
//Do something with data
//This return statement is here only because the conditions in this example
//are mutually exclusive. In case there is data that can be processed by multiple
//commands, the return statement would not be put here.
return;
}
if (Next != null)
{
Next.Execute(data);
}
}
}
class CommandB : Command
{
protected override bool DataCheck(LegacyData data)
{
return data.Type == "B";
}
public override void Execute(LegacyData data)
{
if (DataCheck(data))
{
//Do something with data
//This return statement is here only because the conditions in this example
//are mutually exclusive. In case there is data that can be processed by multiple
//commands, the return statement would not be put here.
return;
}
if (Next != null)
{
Next.Execute(data);
}
}
}
class CommandC : Command
{
protected override bool DataCheck(LegacyData data)
{
return data.Type != "A" && data.Type != "B";
}
public override void Execute(LegacyData data)
{
if (DataCheck(data))
{
//Do something with data
//This return statement is here only because the conditions in this example
//are mutually exclusive. In case there is data that can be processed by multiple
//commands, the return statement would not be put here.
return;
}
if (Next != null)
{
Next.Execute(data);
}
}
}
class SuperCommand
{
private List<LegacyData> datas;
public SuperCommand(List<LegacyData> datas){ this.datas = datas; }
private Command initialCommand;
public SuperCommand()
{
CommandA commandA = new CommandA();
CommandB commandB = new CommandB();
CommandC commandC = new CommandC();
commandA.Next = commandB;
commandB.Next = commandC;
initialCommand = commandA;
}
public void Execute()
{
foreach (LegacyData data in datas)
{
initialCommand.Execute(data);
}
}
}
Con questo approccio, avresti completamente disaccoppiato SuperCommand dalla logica nelle classi di comando. L'unica cosa che lega SuperCommand con le classi di comando concrete sarebbe la loro istanziazione e il collegamento nel costruttore. La logica su quale comando verrà eseguito verrebbe ricollocata nelle classi Command, che è possibile testare facilmente.