InventoryCommand abstract class

The first thing to point out about the initial console application is that the team is using object-oriented programming (OOP) to create a standard way of handling commands. What the team learned from this initial design is that all commands will contain a RunCommand() method that will return two Booleans indicating whether the command was successful and whether the program should terminate. For example, the HelpCommand() will simply display a help message to the console and should not cause the program to end. The two return Booleans would then be true, to indicate that the command ran successfully and false, to indicate that the application should not terminate. The following shows the initial version:

The ... indicates additional statements and, in this particular example, additional Console.WriteLine() statements.
public class HelpCommand
{
public bool RunCommand(out bool shouldQuit)
{
Console.WriteLine("USAGE:");
Console.WriteLine(" addinventory (a)");
...
Console.WriteLine("Examples:");
...

shouldQuit = false;
return true;
}
}

The QuitCommand will display a message and then cause the program to end. The initial QuitCommand was as follows:

public class QuitCommand
{
public bool RunCommand(out bool shouldQuit)
{
Console.WriteLine("Thank you for using FlixOne Inventory Management System");

shouldQuit = true;
return true;
}
}

The team decided to either create an interface that both classes implement, or an abstract class that both classes inherit from. Both could have achieved the desired dynamic polymorphism but the team chose to use an abstract class as all commands will have shared functionality.

In OOP and in particular C#, polymorphism is supported in three main ways: function overloading, generics, and subtyping or dynamic polymorphism. 

Using the Abstract Factory Design pattern, the team created an abstract class that commands would inherit from, InventoryCommand. The InventoryCommand class has a single method, RunCommand, that will perform the command and return whether the command was successfully executed and whether the application should quit. The class is abstract, meaning the class contains one or more abstract methods. In this case, the InternalCommand() method is abstract and the intent is that classes deriving from the InventoryCommand class will implement the InternalCommand method with the specific command functionality. For example, QuitCommand will extend InventoryCommand and provide a concrete implementation for the InternalCommand() method. The following snippet shows the InventoryCommand abstract class with the abstract InternalCommand() method:

public abstract class InventoryCommand
{
private readonly bool _isTerminatingCommand;
internal InventoryCommand(bool commandIsTerminating)
{
_isTerminatingCommand = commandIsTerminating;
}
public bool RunCommand(out bool shouldQuit)
{
shouldQuit = _isTerminatingCommand;
return InternalCommand();
}

internal abstract bool InternalCommand();
}

The abstract method would then be implemented in each derived class, as illustrated with the HelpCommand. The HelpCommand simply prints some information to the console and then returns true, indicating that the command was executed successfully:

public class HelpCommand : InventoryCommand
{
public HelpCommand() : base(false) { }

internal override bool InternalCommand()
{
Console.WriteLine("USAGE:");
Console.WriteLine(" addinventory (a)");
...
Console.WriteLine("Examples:");
...
return true;
}
}

The development team then decided on making two additional changes to the InventoryCommand. The first thing they did not like was how the shouldQuit Boolean was being returned as an out variable. Thus, they decided to use the new tuples feature of C# 7 to instead return a single Tuple<bool,bool> object as follows:

public (bool wasSuccessful, bool shouldQuit) RunCommand()
{
/* additional code hidden */

return (InternalCommand(), _isTerminatingCommand);
}
Tuple
The tuple is a C# type that provides a lightweight syntax for packaging multiple values into a single object easily. The disadvantage over defining a class is you lose inheritance and other object-oriented functionality. For more information, please see https://docs.microsoft.com/en-us/dotnet/csharp/tuples.

The other change was to introduce another abstract class to indicate whether the command was a non-terminating command; in other words, a command that does not cause the solution to quit or end.

As shown in the following code, this command is still abstract as it does not implement the InternalCommand method of InventoryCommand, but it passes a false value to the base class:

internal abstract class NonTerminatingCommand : InventoryCommand
{
protected NonTerminatingCommand() : base(commandIsTerminating: false)
{
}
}

The advantage here is now commands that do not cause the application to end – in other words, are non-terminating – now have a simpler definition:

internal class HelpCommand : NonTerminatingCommand
{
internal override bool InternalCommand()
{
Interface.WriteMessage("USAGE:");
/* additional code hidden */

return true;
}
}

The following class diagram shows the inheritance of the InventoryCommand abstract class:

There is only one terminating command, QuitCommand, while the other commands extend the NonTerminatingCommand abstract class. It is also worth noting that only the AddInventoryCommand and UpdateQuantityCommand require parameters and the use of the IParameterisedCommand is explained later in the Liskov Substitution Principle section. Another subtle point in the diagram is that all the types, other than the base InventoryCommand, are not public (visible to external assemblies). This will become relevant in the Access modifiers section later in the chapter. 

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.227.102.124