C
C#15mo ago
LazyGuard

❔ Refactoring strategy pattern to a simpler code

I have the following code and I want te refactor it to a less-boiler-plate code. Wha'ts suposed to do is that the Handle method should take a product as input and 1.decides to which output system it needs to send information (depending on some configuration and on the product itself). There could be more thant 1 output systems to send the product to. 2. convert the Product to the appropriate format for chosen output systems.
3. send to those systems
public class XMLHandler
{
private readonly IOutputSystemStrategyFactory _strategyFactory;
private readonly IOutputSystemDecider _outputSystemsDecider;

public XMLHandler(IOutputSystemStrategyFactory strategyFactory, IOutputSystemDecider outputSystemsDecider)
{
_strategyFactory = strategyFactory;
_outputSystemsDecider = outputSystemsDecider;
}

public void Handle(Product product)
{
IEnumerable<OutputSystem> outputSystems = _outputSystemsDecider.GetOutputSystems(product);

foreach (OutputSystem outputSystem in outputSystems)
{
IOutputSystemStrategy strategy = _strategyFactory.Create(outputSystem);
strategy.GenerateAndSend(product);
}
}
}
public class XMLHandler
{
private readonly IOutputSystemStrategyFactory _strategyFactory;
private readonly IOutputSystemDecider _outputSystemsDecider;

public XMLHandler(IOutputSystemStrategyFactory strategyFactory, IOutputSystemDecider outputSystemsDecider)
{
_strategyFactory = strategyFactory;
_outputSystemsDecider = outputSystemsDecider;
}

public void Handle(Product product)
{
IEnumerable<OutputSystem> outputSystems = _outputSystemsDecider.GetOutputSystems(product);

foreach (OutputSystem outputSystem in outputSystems)
{
IOutputSystemStrategy strategy = _strategyFactory.Create(outputSystem);
strategy.GenerateAndSend(product);
}
}
}
8 Replies
LazyGuard
LazyGuardOP15mo ago
public interface IOutputSystemStrategy
{
void GenerateAndSend(Product product);
}

public class ERP1Strategy : IOutputSystemStrategy
{
public void GenerateAndSend(Product product)
{
}
}

public class ERP2Strategy : IOutputSystemStrategy
{
public void GenerateAndSend(Product product)
{
}
}

public class ERP3Strategy : IOutputSystemStrategy
{
public void GenerateAndSend(Product product)
{
}
}

public interface IOutputSystemStrategyFactory
{
IOutputSystemStrategy Create(OutputSystem outputSystem);
}


public class OutputSystemStrategyFactory : IOutputSystemStrategyFactory
{
public IOutputSystemStrategy Create(OutputSystem outputSystem)
{
switch (outputSystem)
{
case OutputSystem.ERP1:
return new ERP1Strategy();
case OutputSystem.ERP2:
return new ERP2Strategy();
case OutputSystem.ERP3:
return new ERP3Strategy();
default:
throw new ArgumentException("Invalid output system");
}
}
}

public interface IOutputSystemDecider
{
IEnumerable<OutputSystem> GetOutputSystems(Product product);
}
public interface IOutputSystemStrategy
{
void GenerateAndSend(Product product);
}

public class ERP1Strategy : IOutputSystemStrategy
{
public void GenerateAndSend(Product product)
{
}
}

public class ERP2Strategy : IOutputSystemStrategy
{
public void GenerateAndSend(Product product)
{
}
}

public class ERP3Strategy : IOutputSystemStrategy
{
public void GenerateAndSend(Product product)
{
}
}

public interface IOutputSystemStrategyFactory
{
IOutputSystemStrategy Create(OutputSystem outputSystem);
}


public class OutputSystemStrategyFactory : IOutputSystemStrategyFactory
{
public IOutputSystemStrategy Create(OutputSystem outputSystem)
{
switch (outputSystem)
{
case OutputSystem.ERP1:
return new ERP1Strategy();
case OutputSystem.ERP2:
return new ERP2Strategy();
case OutputSystem.ERP3:
return new ERP3Strategy();
default:
throw new ArgumentException("Invalid output system");
}
}
}

public interface IOutputSystemDecider
{
IEnumerable<OutputSystem> GetOutputSystems(Product product);
}
LazyGuard
LazyGuardOP15mo ago
for example Here , A product with sellerId 4 will only be sent to ERP 3 whereas a product with sellerId 3 will be sent to both ERP 1 and ERP 2 https://i.stack.imgur.com/dzLW8.png ERPs are the external systems
LazyGuard
LazyGuardOP15mo ago
Any help 🙄 ?
Mayor McCheese
Mayor McCheese15mo ago
Are you trying to maintain the strategy pattern? Design patterns are generally boilerplate heavy
Erroneous Fatality
The code as is is quite good. The only room to reduce boilerplate would be if this implementation is overkill for the purpose. Do your IOutputSystemStrategy implementations depend on different dependencies (libraries, packages); are they defined in different projects/assemblies? If not, if they're all in the same project (alongside the factory definition) already, then you don't need the strategy pattern here. You could just switch on the outputSystem.Type inside your foreach in order to determine where to send the data, and from then on it seems the codeflow is the same for all types.
LazyGuard
LazyGuardOP15mo ago
@Erroneous Fatality what do you mean by switching on the outputSystem.Type instead of hte foreach ? because a product could be sent to more than one outputsystems no it's not the same flow, for each Output system there is a completely different logic I must generate different XML, send to different output systems etc. the output systems are completly out-of-process My app communicate with those systems either by Kafka or by HTTP calls
Erroneous Fatality
Not instead, inside 🙂 Just move your logic from the strategy pattern directly to the service code if you don't expect to have different configurations for a single output type.
Accord
Accord15mo ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.

Did you find this page helpful?