Input strings as dictionary keys

Viewed 73

I have a console program where we have some fictitious CLI commands, for example` create, show, exit, assign and etc, like that

class Program
    {
        static void Main()
        {
            new TicketProcessor().Start();
        }
    }

    public class TicketProcessor
    {
        private readonly Dictionary<int, Ticket> _tickets = new Dictionary<int, Ticket>();
        private int _counter = 0;

        public void Start()
        {
            Console.WriteLine("\n\nSUPPORT CLI");
            while (true)
            {
                Console.WriteLine("\n\nAvailable commands:");
                Console.WriteLine("create %title% - create a new ticket");
                Console.WriteLine("show %ticket id% - show the ticket");
                Console.WriteLine("comment %ticket id% %comment% - add a comment to the ticket");
                Console.WriteLine("assign %ticket id% %user name% - assign the ticket");
                Console.WriteLine("close %ticket id% - close the ticket");
                Console.WriteLine("list- show all tickets");
                Console.WriteLine("q - exit");
                Console.WriteLine();

                var input = Console.ReadLine();
                if (input.Equals("q")) break;

                if (input.Equals("list"))
                {
                    foreach (var ticket in _tickets)
                    {
                        Console.WriteLine($"{ticket.Value.Id} | {ticket.Value.Title}");
                    }

                    continue;
                }

                if (input.StartsWith("create "))
                {
                    _counter++;
                    _tickets[_counter] = new Ticket
                    {
                        Id = _counter,
                        Title = input.Substring(7, input.Length - 7),
                        CurrentState = Ticket.State.Open,
                        Comments = new List<string>()
                    };
                    Console.WriteLine($"{_counter} has been created ");
                    continue;
                }

                if (input.StartsWith("show "))
                {
                    var id = int.Parse(input.Split(' ')[1]);
                    _tickets[id].Show();
                    continue;
                }

                if (input.StartsWith("comment "))
                {
                    var id = int.Parse(input.Split(' ')[1]);
                    var commentPrefix = 8 + input.Split(' ')[1].Length + 1;
                    var comment = input.Substring(commentPrefix, input.Length - commentPrefix);
                    var ticket = _tickets[id];
                    ticket.Comments.Add(comment);
                    ticket.CommentsCount++;
                    Console.WriteLine($"new comment has been added into {id}");
                    continue;
                }

                if (input.StartsWith("assign "))
                {
                    var id = int.Parse(input.Split(' ')[1]);
                    var usernamePrefix = 7 + input.Split(' ')[1].Length + 1;
                    var username = input.Substring(usernamePrefix, input.Length - usernamePrefix);
                    var ticket = _tickets[id];
                    ticket.Comments.Add("assigned " + username + " " + DateTime.UtcNow);
                    ticket.CommentsCount++;
                    ticket.AssignedToUser = username;
                    ticket.CurrentState = Ticket.State.InProgress;
                    Console.WriteLine($"{id} has been assigned to {username}");
                    continue;
                }

                if (input.StartsWith("close "))
                {
                    var id = int.Parse(input.Split(' ')[1]);
                    var ticket = _tickets[id];
                    ticket.CurrentState = Ticket.State.Closed;
                    ticket.Comments.Add("closed " + DateTime.UtcNow);
                    ticket.CommentsCount++;
                    Console.WriteLine($"{id} has been closed ");
                }
            }
        }
    }

This is not clear code and clean architecture as well.

I try to change this into clear architecture. Firstly, I created CommandHandler class and extracted if blocks into methods in , and singled out TicketProcessor Class from Program Class like this.

public class TicketProcessor
    {
        private readonly Func<string> _inputProvider;
        private readonly Action<string> _outputProvider;
        private readonly CommandHandler _commandHandler;
        public TicketProcessor(Func<string> inputProvider, Action<string> outputProvider, CommandHandler commandHandler)
        {
            _inputProvider = inputProvider;
            _outputProvider = outputProvider;
            _commandHandler = commandHandler;
        }

        public void Start()
        {
            _outputProvider("\n\nSUPPORT CLI");
            _outputProvider($"\n\nAvailable commands:\n{ string.Join("\n", _commandHandler.GetAvailableCommands())}");

            Console.WriteLine();
            var input = _inputProvider() ?? string.Empty;

            if (!_commandHandler.GetAvailableCommands().Contains(input))
            {
                _outputProvider("there is no such command");
                return;
            }

            _commandHandler.GetCommand(input);

            Console.WriteLine();
        }
    }

The CommandHandler class is like so.

public class CommandHandler
    {
        private readonly Dictionary<int, Ticket> _tickets = new Dictionary<int, Ticket>();
        private readonly Dictionary<string, Action<string>> _commands;
        private readonly Func<string> _inputProvider;
        private readonly Action<string> _outputProvider;
        private int _counter = 0;


        public CommandHandler(Func<string> inputProvider, Action<string> outputProvider)
        {
            _inputProvider = inputProvider;
            _outputProvider = outputProvider;
            _commands = new Dictionary<string, Action<string>>()
            {
                {"create %title% - create a new ticket", Create },
                {"show %ticket id% - show the ticket", Show },
                {"comment %ticket id% %comment% - add a comment to the ticket", Comment },
                {"assign %ticket id% %user name% - assign the ticket", Assign },
                {"close %ticket id% - close the ticket", Close },
                {"list- show all tickets", List },
                {"q - exit", Exit }
            };
        }

        public void GetCommand(string commandName)
        {
            _commands[commandName](commandName);
        }

        public IEnumerable<string> GetAvailableCommands()
        {
            return _commands.Keys;
        }

        private void Exit(string input)
        {
            if (input.Equals("q"))
            {
                Environment.Exit(0);
            }
        }

        private void List(string input)
        {
            if (input.Equals("list"))
            {
                foreach (var ticket in _tickets)
                {
                    _outputProvider($"{ticket.Value.Id} | {ticket.Value.Title}");
                }

                return;
            }
        }

        private void Close(string input)
        {
            if (input.StartsWith("close "))
            {
                var id = int.Parse(input.Split(' ')[1]);
                var ticket = _tickets[id];
                ticket.CurrentState = Ticket.State.Closed;
                ticket.Comments.Add("closed " + DateTime.UtcNow);
                ticket.CommentsCount++;
                Console.WriteLine($"{id} has been closed ");
            }
        }

        private void Assign(string input)
        {
            if (input.StartsWith("assign "))
            {
                var id = int.Parse(input.Split(' ')[1]);
                var usernamePrefix = 7 + input.Split(' ')[1].Length + 1;
                var username = input.Substring(usernamePrefix, input.Length - usernamePrefix);
                var ticket = _tickets[id];
                ticket.Comments.Add("assigned " + username + " " + DateTime.UtcNow);
                ticket.CommentsCount++;
                ticket.AssignedToUser = username;
                ticket.CurrentState = Ticket.State.InProgress;
                _outputProvider($"{id} has been assigned to {username}");
                return;
            }
        }

        private void Comment(string input)
        {
            if (input.StartsWith("comment "))
            {
                var id = int.Parse(input.Split(' ')[1]);
                var commentPrefix = 8 + input.Split(' ')[1].Length + 1;
                var comment = input.Substring(commentPrefix, input.Length - commentPrefix);
                var ticket = _tickets[id];
                ticket.Comments.Add(comment);
                ticket.CommentsCount++;
                _outputProvider($"new comment has been added into {id}");
                return;
            }
        }

        private void Show(string input)
        {
            if (input.StartsWith("show "))
            {
                var id = int.Parse(input.Split(' ')[1]);
                _tickets[id].Show();
                return;
            }
        }

        private void Create(string input)
        {
            if (input.StartsWith("create "))
            {
                _counter++;
                _tickets[_counter] = new Ticket
                {
                    Id = _counter,
                    Title = input.Substring(7, input.Length - 7),
                    CurrentState = Ticket.State.Open,
                    Comments = new List<string>()
                };
                _outputProvider($"{_counter} has been created ");
                return;
            }
        }
    }

Program class looks like so.

class Program
    {
        static void Main()
        {
            var command = new CommandHandler(Console.ReadLine, Console.WriteLine);
            var ticket = new TicketProcessor(Console.ReadLine, Console.WriteLine, command);
            while (true)
            {
                ticket.Start();
            }
        }
    }

The problem is that when I type create title, or show 1 (1 is ticket id for example), assigne and other commands in the console, the methods will not be called because in _commands dictionary, the key's are specific strings.

What else to use instead of a dictionary to solve this problem?

PS. Ticket class is not attached.

Thanks in advance.

0 Answers
Related