samedi 29 janvier 2022

Is it ok to have the client and the invoker modifying the concrete ICommand, in the command pattern design?

I am trying out this flavor of the command pattern, for practice purposes, where the concrete implementation of the ICommand needs two pieces of data in order to properly execute. As of right now, the Client provides the initial data point via the command constructor, but it has no idea how to provide the second datapoint, which can only be set via a separate method SetPreparar(IStaff preparer). I have delegated that responsibility to the Invoker class.

I have seen various flavors of the command pattern, but I have not seen one in which both the client and the invoker are setting state.
I really like how clean it looks and feels, but the fact that 2 classes are changing state bothers me a little.

Hence the question in the title.

Below is a Console App written in .NET 6. Can I get a code review, I guess?

var cook = new Cook();
var bartender = new Bartender();
var bobWaiter = new Waiter(cook, bartender);
var customer = new Customer(bobWaiter);

customer.OrderFood("Pepperoni Pizza");
customer.OrderDrink("Iced tea");
customer.ThankYouThatsAll();

Console.ReadLine();


class Customer
{

    IWaiterInvoker _waiter;

    public Customer(IWaiterInvoker waiter)
    {
        _waiter = waiter;
    }

    public void OrderFood(string dishName)
    {
        var foodOrderCommand = new OrderFoodCommand(dishName);
        _waiter.TakeFoodOrder(foodOrderCommand);
    }

    public void OrderDrink(string bevName)
    {
        var beverageCommand = new OrderBeverageCommand(bevName);
        _waiter.TakeDrinkOrder(beverageCommand);
    }

    public void ThankYouThatsAll()
    {
        _waiter.ExecuteCommands();
    }

}

class Waiter : IWaiterInvoker
{
    IStaff _cook;
    IStaff _bartender;

    public List<IOrderCommand> allCommands { get; private set; }

    public Waiter(IStaff cook, IStaff preparer)
    {
        _cook = cook;
        _bartender = preparer;
        allCommands = new List<IOrderCommand>();
    }

    public void TakeFoodOrder(IOrderCommand command)
    {
        command.SetPreparer(_cook);
        allCommands.Add(command);

    }

    public void TakeDrinkOrder(IOrderCommand command)
    {
        command.SetPreparer(_bartender);
        allCommands.Add(command);
    }

    public void ExecuteCommands()
    {
        foreach (var cmd in allCommands)
        {
            cmd.Execute();
        }
    }
}


class Cook : IStaff
{
    public void Prepare(string item)
    {
        Console.WriteLine($"You dish {item} is ready");
    }
}


class Bartender : IStaff
{
    public void Prepare(string item)
    {
        Console.WriteLine($"Your drink {item} is ready");
    }

}

public interface IStaff
{
    void Prepare(string item);
}

public interface IOrderCommand
{
    void SetPreparer(IStaff preparer);
    void Execute();
}

public interface IWaiterInvoker
{
    List<IOrderCommand> allCommands { get; }
    void TakeFoodOrder(IOrderCommand command);
    void TakeDrinkOrder(IOrderCommand command);
    void ExecuteCommands();
}

public class OrderBeverageCommand : IOrderCommand
{
    string _beverage;
    IStaff _preparer;

    public OrderBeverageCommand(string beverage)
    {
        _beverage = beverage;
    }


    public void Execute()
    {
        _preparer.Prepare(_beverage);
    }

    public void SetPreparer(IStaff preparer)
    {
        _preparer = preparer;
    }
}


public class OrderFoodCommand : IOrderCommand
{
    string _dishName;
    IStaff _preparer;

    public OrderFoodCommand(string dishName)
    {
        _dishName = dishName;
    }

    public void Execute()
    {
        _preparer.Prepare(_dishName);
    }

    public void SetPreparer(IStaff preparer)
    {
        _preparer = preparer;
    }
}

Aucun commentaire:

Enregistrer un commentaire