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.

Stelios Adamantidis
  • 1,866
  • 21
  • 36
Saber Amani
  • 6,409
  • 12
  • 53
  • 88

2 Answers2

29

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);
Dennis Traub
  • 50,557
  • 7
  • 93
  • 108
  • 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? – Saber Amani Jan 14 '12 at 16:01
  • 4
    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`. You can just impement `ICommand` add the `Result` property to the `CalculateSalaryClass`. – Dennis Traub Jan 14 '12 at 16:46
  • 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. – Daniel Hári May 13 '16 at 13:02
  • 3
    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. – Daniel Hári May 13 '16 at 13:08
  • 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? – Abstraction is everything. May 10 '17 at 16:54
  • 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? – BenKoshy Feb 27 '18 at 23:51
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);
    }
}
Manish Basantani
  • 16,931
  • 22
  • 71
  • 103
  • 4
    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 ? – Saber Amani Jan 14 '12 at 14:53
  • @SaberAmani: Two ways, either implement ICommand that returns null or have a method/property called `GetResult()`. – Spoike Jan 14 '13 at 12:55