C# правильный способ использования шаблона стратегии - PullRequest
0 голосов
/ 09 января 2020

Я пытаюсь реорганизовать мой код. В настоящее время у меня есть разные имена методов для аналогичного вида функциональности, как показано ниже.

public interface IReminderService
{
    Task GenerateInviteReminders(string executedBy);
    Task GenerateBookingReminders(string executedBy);
}

Но я хочу использовать что-то вроде ниже. Но не уверен, как передать параметры в случае переключения, чтобы установить стратегию. Интерфейсы вводятся с использованием IO C. Или, пожалуйста, дайте мне знать правильный способ рефакторинга моего кода.

public interface IReminderStrategy
{
    Task GenerateReminders(string executedBy);
}

public class StrategyA : IReminderStrategy
{
    public StrategyA(IInterfaceA a, IInterface b)
    {}
}

public class StrategyB : IReminderStrategy
{
    public StrategyB(IInterfaceA a, IInterface b)
    {}
}   


public class ExampleService {
    private readonly IInterfaceA _a;
    private readonly IInterfaceB _b;
    public ExampleService(
        IInterfaceA a,
        IInterfaceB b
    ) {}
    switch case(string messageType)
    {
        IReminderStrategy strategy;
        case "A":
            strategy = new StrategyA(?????)
            break;
        case "B":
            strategy = new StrategyB(?????)
            break;          
    }
}

Ответы [ 3 ]

0 голосов
/ 09 января 2020

Вам потребуется еще один класс (ConcreteClass) для реализации метода интерфейса и передачи ваших объектов (StrategyA или StrategyB) в качестве параметров в новый объект этого класса (ConcreteClass), а затем при необходимости вызовите метод.

switch (message)
        {
            case "A":
                concreteObject.SampleMethod(new StrategyA());
                break;
            case "B":
                concreteObject.SampleMethod(new StrategyB());
                break;
            default:                    
                break;
        }
.... 
concreteObject.Execute(inputMessage)

class Concrete
{
    IReminderStrategy _reminderStrategy;
    public void SampleMethod(IReminderStrategy reminderStrategy)
    {
        _reminderStrategy = reminderStrategy
    }

    public void Execute(string message)
    {
        _reminderStrategy.GenerateReminders(message);
    }
}
0 голосов
/ 09 января 2020

Прежде всего, я часто использую шаблоны стратегий или шаблонных методов, поскольку вы используете динамическую c диспетчеризацию или полиморфизм, и вы в основном избавляетесь от блоков if-else. Я имею в виду, что вы помещаете эту логику c в одно место, чтобы не создавать if-элементы, которые разбросаны по нескольким местам. Для дальнейшего изучения вы можете сравнить их с функциями более высокого порядка в функциональном программировании.

public interface IReminderStrategy
{
    Task GenerateReminders(string executedBy);
}

public class InviteReminder : IReminderStrategy
{
    private IInterfaceA _a;
    private IInterfaceB _b;
    public InviteReminder(IInterfaceA a, IInterface b){
       _a = a; _b = b;
    }

    public Task GenerateReminders(String executedBy) {
       _a.doSomething;
       _b.doSomething;
       //do invite reminder specific actions here.
    }

}

public class BookingReminder : IReminderStrategy
{
    private IInterfaceA _a;
    private IInterfaceB _b;
    public BookingReminder(IInterfaceA a, IInterface b){
       _a = a; _b = b;
    }

    public Task GenerateReminders(String executedBy) {
       _a.doSomething;
       _b.doSomething;
       //do booking reminder specific actions here.
    }
}   


public static class ReminderFactory {

    //If there will be no DI then remove injects and static and instantiate the object with dependencies.
    @Inject
    private readonly IInterfaceA _a;

    @Inject
    private readonly IInterfaceB _b;

    /* made the class as static so as you said we will be using a DI container.
    public ReminderFactory(IInterfaceA a, IInterfaceB b) {
       _a = a; 
       _b = b;
    }
    */

    public IReminderStrategy getReminder(String messageType) {
       switch case(messageType)
       {
          IReminderStrategy strategy;
          case "invite":
             strategy = new InviteReminder(_a, _b)
             break;
          case "book":
             strategy = new BookingReminder(_a, _b)
             break; 
       }         
    }
}

1) создать и передать стратегию (для педагогических целей, т.е. для наглядной иллюстрации.)

затем где-то и на шаг раньше в клиенте:

IReminderStrategy reminderStrategy = ReminderFactory.getReminder("invite");
shopService.shop(reminderStrategy);

наконец в клиенте:

public class ShopService {
   public void shop(IReminderStrategy reminderStrategy) {
      reminderStrategy.GenerateReminders("taha");
   }
}

2) или напрямую:

public class ShopService {
   public void shop() {
      //...
      IReminderStrategy reminderStrategy = ReminderFactory.getReminder("invite");
      reminderStrategy.GenerateReminders("taha");
      //...
   }
}

и, возможно, в другом сервисе:

public class TravelService myService() {
   public void travel() {
      //travel preparation
      IReminderStrategy reminderStrategy = ReminderFactory.getReminder("book");
      reminderStrategy.GenerateReminders("admin");
      //other travel things or maybe do something with the result.;
   }
}
0 голосов
/ 09 января 2020

Ваш контекстный класс (ExampleService) не должен знать, что существуют разные реализации конкретного поведения (стратегии). Вместо того, чтобы контекстный класс отвечал за создание экземпляра стратегии, вы должны вместо этого передать стратегию как ее зависимость. Таким образом, вы добьетесь слабой связи, поскольку создание экземпляров может зависеть от множества факторов, выходящих за рамки контекста класса, и это также может быть довольно сложным. Это также позволяет вам добавлять больше стратегий в будущем, не изменяя ExampleService.

public class ExampleService 
{
    private readonly IReminderStrategy strategy;

    public ExampleService(IReminderStrategy strategy)
    {
        this.strategy = strategy;
    }
}

Решение о том, какой тип стратегии предоставлять, должно быть делегировано контейнеру Io C. Что-то вроде

if (useA)
{
    // bind IReminderStrategy to StrategyA
}
else
{
    // bind IReminderStrategy to StrategyB
} 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...