Get result of executed method in Command Pattern
Asked Answered
T

2

12

Currently I'm trying to implement Transaction Script pattern (Exactly how Martin Fowler described by using Command Pattern) in a simple test project, everything just work fine, the problem is where I don't know how to get result(s) when specified method executed in concrete class which is inherited from ICommand interface.

Let's show you some code to clarify what functionality I have. I've a simple CalculateSalaryCommand class which inherited from ICommand interface

public class CalculateSalaryCommand : ICommand
{
    private readonly CalculateSalaryTS _salaryTs;
    private readonly int _hour;
    private readonly int _salaryPerHour;

    public CalculateSalaryCommand(CalculateSalaryTS salaryTs, int hour, int salaryPerHour)
    {
        _salaryTs = salaryTs;
        _hour = hour;
        _salaryPerHour = salaryPerHour;
    }

    public void Execute()
    {
        _salaryTs.CalculateSalary(_hour, _salaryPerHour);
    }
}

and a simple Transaction Script class named CalculateSalaryTS

public class CalculateSalaryTS {
    public void CalculateSalary(int _hour, int _salaryPerHour) {
        Result = _hour * _salaryPerHour;
    }
}

as you can see I pass the instance of to concrete command class, then inside the Execute method I execute a operations from that instance. Well, everything just look good. but there is a problem I can't return the result of executed method which is should be a integer. To handle this problem, I decided to add some code to Transaction Script layer which each transaction should inherit from a generic ITransactionResult interface, which is look like following:

public interface ITransactionResult<TResult>
{
    TResult Result { get; set; }
}

Then CalculateSalaryTS class became like this :

public class CalculateSalaryTS : ITransactionResult<Int32> {

    public void CalculateSalary(int _hour, int _salaryPerHour) {
        Result = _hour * _salaryPerHour;
    }

    public int Result { get; set; }

}

Usage :

    var script = new CalculateSalaryTS();
    var command = new CalculateSalaryCommand(script, 10, 20);           
    command.Execute();
    Console.WriteLine("Salary is {0}", script.Result);

I know this way has its own limitation but I don't have any choice till you give me another idea to handle this situation.

Thanks in advance.

Tal answered 14/1, 2012 at 14:39 Comment(0)
P
30

If you absolutely need to get the result immediately after command execution, you could store the result in the command object:

public interface ICommandWithResult<T> : ICommand
{
  T Result { get; }
}

public class CalculateSalaryCommand : ICommandWithResult<int>
{
  public int Result { get; private set; }

  // ...

  public void Execute()
  {
    _salaryTs.CalculateSalary(_hour, _salaryPerHour);
    this.Result = _salaryTs.Result;
  }
}

// Usage:

var command = new CalculateSalaryCommand(new CalculateSalaryTS(), 10, 20);
command.Execute();
Console.WriteLine("Salary is {0}", command.Result);
Placencia answered 14/1, 2012 at 15:12 Comment(6)
Dennis thanks for reply. You preferred a great solution. But since I'm new to design pattern's concepts I get confused about adding additional functionality to ICommand behavior. Is it correct?Tal
I don't think there's a problem with extending your commands as needed. Design Patterns are meant as a guidance as how to solve specific and recurring problems. They're not set in stone but rather a foundation on that you can build. In your specific case you don't even need to add the interface ICommandWithResult<T>. You can just impement ICommand add the Result property to the CalculateSalaryClass.Placencia
Iam also in the same situation, but I think command pattern is not what I ougth to be use. I think this type of confusion raises when people use a different pattern that their problem needs.Hello
I think command pattern's power is that you pass the flow of control to another component to let it decide the schedule of the execution (put in a queue for example). But if you pass flow of control you lose return value. If you want to execute the command immediately, and get return value you don't need to use command pattern.Hello
What is the point of even using the Command Pattern this way? Why would you not just use The Visitor Pattern, on what ever container is spitting your simple transactions out as receivers to a Pattern that is being thrown on its lips? Or perhaps a Decorator?Crawfish
isn't this a liskov substitution violation? isn't the command not merely an Icommand anymore, it's an Icommand + a result property: this means that we'd have to query whether it's a calculateSalaryCommand before asking for the result property?Warlord
A
6

I think you are looking for a command pattern which is capable of returning result.

so,

    interface ICommand<TResult>
    {
       TResult Execute();
    }


public class CalculateSalaryCommand : ICommand<int>
{
    private readonly CalculateSalaryTS _salaryTs;
    private readonly int _hour;
    private readonly int _salaryPerHour;

    public CalculateSalaryCommand(CalculateSalaryTS salaryTs, int hour, int salaryPerHour)
    {
        _salaryTs = salaryTs;
        _hour = hour;
        _salaryPerHour = salaryPerHour;
    }

    public int Execute()
    {
        return _salaryTs.CalculateSalary(_hour, _salaryPerHour);
    }
}
Avlona answered 14/1, 2012 at 14:48 Comment(2)
Command Pattern's method should be void, let's imagine you are right, what about if I want to execute a method which is void. what should I do ?Tal
@SaberAmani: Two ways, either implement ICommand<Object> that returns null or have a method/property called GetResult().Quadroon

© 2022 - 2024 — McMap. All rights reserved.