简体   繁体   中英

Correct way to implement strategy design Pattern in C#

I have a scenario wherein there are multiple conditions and I have to write a code in such a way that it should be open for extension and not for modification so I went with the strategy design pattern, below is my code, let me know if I'm on the correct path and need some guidance on the code written.

// Is this correct way to call it, how to apply dependency injection?
// You can find this code in the end
BaseOrderProcessing baseOrderProcessing =
    new BaseOrderProcessing(
        new BaseSubscribe(
            new SubscribeService(
                Subscribe)));  

Here is the actual code:

public interface IBaseOrderProcessing
{
    void ProcessOrder();
}

public class BaseOrderProcessing : IBaseOrderProcessing
{
    private IBaseOrderProcessing _baseOrderProcessing = null;
    public BaseOrderProcessing(IBaseOrderProcessing baseOrderProcessing)
    {
        _baseOrderProcessing = baseOrderProcessing;
    }
    public virtual void ProcessOrder()
    {
        _baseOrderProcessing.ProcessOrder();
    }
}

public interface ISubscribeService
{
    SubscribeType SubscribeType { get; set; }
    void ActivateSubscribe();

    void UpgradeSubscribe();
}

// Strategy Pattern 1  => Subscribe is one of the "if" condition
public class BaseSubscribe : IBaseOrderProcessing
{
    private ISubscribeService _SubscribeService = null;
    public BaseSubscribe(ISubscribeService SubscribeService)
    {
        _SubscribeService = SubscribeService;
    }
    
    public void ProcessOrder()
    {
        if (_SubscribeService.SubscribeType == SubscribeType.ACTIVATE)
            _SubscribeService.ActivateSubscription();

        if (_SubscribeService.SubscribeType == SubscribeType.UPGRADE)
            _SubscribeService.UpgradeSubscription();
        
    }
}

// Writing another class to simplify is correct ?????
public class SubscribeService : ISubscribeService
{
    private SubscribeDetails _Subscribedetails = null;

    public SubscribeType SubscribeType { get; set; }

    public SubscribeService(SubscribeDetails Subscribedetails)
    {
        _Subscribedetails = Subscribedetails;
        SubscribeType = Subscribedetails.SubscribeType;
    }
    public void ActivateSubscription()
    {
        // Code to save the Subscribe details in the database
        Console.WriteLine(
            $"\n\nSubscribe {_Subscribedetails.SubscribeId} for " +
            $"{_Subscribedetails.SubscribeName} activated for order Id: {_Subscribedetails.OrderId}" +
            $" from {_Subscribedetails.SubscribeStartDate} to {_Subscribedetails.SubscribeEndDate}");        
    }      

    public void UpgradeSubscription()
    {
        // Code to upgrade the Subscribe details in the database
        Console.WriteLine(
            $"\n\nSubscribe {_Subscribedetails.SubscribeId} for " +
            $"{_Subscribedetails.SubscribeName} upgraded for order Id: {_Subscribedetails.OrderId}" +
            $" from {_Subscribedetails.SubscribeStartDate} to {_Subscribedetails.SubscribeEndDate}");

    }
}  

Client code:

// Is this correct way to call it, how to apply dependency injection?
IBaseOrderProcessing baseOrderProcessing = null;
SubscribeDetails Subscribe = new SubscribeDetails();

Subscribe.OrderId = Guid.NewGuid();
Subscribe.SubscribeId = Guid.NewGuid();
Subscribe.SubscribeName = "Amazon";
Subscribe.SubscribeStartDate = DateTime.Now;
Subscribe.SubscribeEndDate = DateTime.Now.AddDays(30);
if (option == 1)
    Subscribe.SubscribeType = SubscribeType.ACTIVATE;

if (option == 2)
    Subscribe.SubscribeType = SubscribeType.UPGRADE;

baseOrderProcessing =
    new BaseOrderProcessing(
        new BaseSubscribe(
            new SubscribeService(
                Subscribe)));  

You are constructing object that requires runtime details in constructor and possibly (assumption from the post) shares a single common interface with other objects like itself - it's not great, but also not tragic - it just complicates things.

You could apply builder / abstract factory pattern in addition and configure dependency injection to inject said builder / factory service, so that the client could resolve actually needed implementation based on some runtime data.

If possible, you could try to register this (BaseOrderProcessing) service completely from scratch in DI container and inject it as fully configured one if you do not have to resolve it based on some runtime input data but for example you are taking config from a json file while starting this app.

You could also redesign your service so that it will be injected as uninitialized and the SubscribeDetails will be given to it by some method - it would simplify DI configuration.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM