C# Làm sao thoát khỏi if / switch case quá nhiều?

Câu lệnh điều kiện if hay switch case là thường gặp trong lập trinh. Tuy nhiên khi mà if quá nhiều trong một block code, hay switch case quá nhiều thì nó sẽ gây phức tạp và dễ xảy ra bug. Cũng như khó khăn khi viết Unit Tests. Clean code khuyên rằng không nên dùng quá 4 câu lệnh if trong 1 block code.
Vậy đâu là giải pháp để tránh vấn đề này. Trong .NET có hỗ trợ một kiểu dữ liệu đó là Dictionary. Bạn sẽ gặp đâu đó nói rằng Dictionary còn phức tạp hơn, khó tiếp cận hơn if condition nữa. Điều đó là đúng, tuy nhiên qua các ví dụ dưới đây sẽ giúp bạn thấy dễ dàng làm chủ Dictionary hơn, và tránh phải if else, hay switch case quá nhiều.

Vậy Dictionary là gì?

Dictionary is a data structure for storing a group of objects. Objects are stored as key/value pairs collection which is useful and generic in different object oriented programming languages.

Dictionary can be used for mappings, in-memory cache, tables etc.

Dictionary’s key and value are generic types. In this way delegates can be set as key or value.

Hiểu đơn giản, Dictionary trong C# là một Collections lưu trữ dữ liệu dưới dạng cặp Key – Value. Key đại diện cho 1 khoá giống như chỉ số phần tử của mảng và Value chính là giá trị tương ứng của khoá đó. Ta sẽ dử dụng Key để truy cập đến Value tương ứng.

Chúng ta có bài toán cho phép ứng dụng có thể kết nối đến nhiều loại data source khác nhau. MySql, SqlServer, MongoDb, Redis, Xml…

ConnectionDataHelper.cs

public class ConnectionDataHelper
    {
        public static void ConnectToMySql()
        {
            Console.WriteLine("Connect to MySql");
        }

        public static void ConnectToSqlServer()
        {
            Console.WriteLine("Connect to Sql Server");
        }

        public static void ConnectToMongoDb()
        {
            Console.WriteLine("Connect to MongdoDb");
        }

        public static void ConnectToRedis()
        {
            Console.WriteLine("Connect to Redis");
        }

        public static void ConnectToXml()
        {
            Console.WriteLine("Connect to Xml");
        }
    }

Ví dụ dùng if else.

    
internal class Program
    {
        private static void Main(string[] args)
        {
            DataSource dataSource = DataSource.MySql;
            Console.WriteLine("Connection to DB Source: " + dataSource.ToString());
            if (dataSource == DataSource.MySql)
            {
                ConnectionDataHelper.ConnectToMySql();
            }
            else if (dataSource == DataSource.SqlServer)
            {
                ConnectionDataHelper.ConnectToSqlServer();
            }
            else if (dataSource == DataSource.MongoDb)
            {
                ConnectionDataHelper.ConnectToMongoDb();
            }
            else if (dataSource == DataSource.Redis)
            {
                ConnectionDataHelper.ConnectToRedis();
            }
            else if (dataSource == DataSource.Xml)
            {
                ConnectionDataHelper.ConnectToXml();
            }

            Console.ReadKey();
        }

        private enum DataSource
        {
            MySql,
            SqlServer,
            MongoDb,
            Redis,
            Xml
        }
    }

Cách viết switch case dễ đọc hơn một chút, nhưng vẫn còn dài

internal class Program
    {
        private static void Main(string[] args)
        {
            DataSource dataSource = DataSource.MySql;
            Console.WriteLine("Connection to DB Source: " + dataSource.ToString());
            switch (dataSource)
            {
                case DataSource.MySql:
                    ConnectionDataHelper.ConnectToMySql();
                    break;

                case DataSource.SqlServer:
                    ConnectionDataHelper.ConnectToSqlServer();
                    break;

                case DataSource.MongoDb:
                    ConnectionDataHelper.ConnectToMongoDb();
                    break;

                case DataSource.Redis:
                    ConnectionDataHelper.ConnectToRedis();
                    break;

                case DataSource.Xml:
                    ConnectionDataHelper.ConnectToXml();
                    break;
            }

            Console.ReadKey();
        }

        private enum DataSource
        {
            MySql,
            SqlServer,
            MongoDb,
            Redis,
            Xml
        }
    }

Bây giờ chúng ta thử chuyển sang sử dụng Dictionary.

internal class Program
    {
        private static void Main(string[] args)
        {
            var actionMap = new Dictionary()
            {
                {DataSource.MySql, ConnectionDataHelper.ConnectToMySql},
                {DataSource.SqlServer, ConnectionDataHelper.ConnectToSqlServer},
                {DataSource.MongoDb, ConnectionDataHelper.ConnectToMongoDb},
                {DataSource.Redis, ConnectionDataHelper.ConnectToRedis},
                {DataSource.Xml, ConnectionDataHelper.ConnectToXml},
            };
            DataSource dataSource = DataSource.SqlServer;
            Console.WriteLine("Connection to DB Source: " + dataSource.ToString());
            if (actionMap.ContainsKey(dataSource))
            {
                actionMap[dataSource]();
            }

            Console.ReadKey();
        }

        private enum DataSource
        {
            MySql,
            SqlServer,
            MongoDb,
            Redis,
            Xml
        }
    }

Rõ ràng code đã ngắn gọn hơn rất nhiều. Tất nhiên thực tế các function của chúng ta sẽ phức tạp hơn một chút, có input, output. Bây giờ sửa lại ConnectionDataHelper để nhận vào một connectionString, và return về một trạng thái true/false. IsConnected.

ConnectionDataHelper.cs

    public class ConnectionDataHelper
    {
        public static bool ConnectToMySql(string connectionString)
        {
            Console.WriteLine("Connect to MySql: " + connectionString);
            return true;
        }

        public static bool ConnectToSqlServer(string connectionString)
        {
            Console.WriteLine("Connect to Sql Server: " + connectionString);
            return true;
        }

        public static bool ConnectToMongoDb(string connectionString)
        {
            Console.WriteLine("Connect to MongdoDb: " + connectionString);
            return true;
        }

        public static bool ConnectToRedis(string connectionString)
        {
            Console.WriteLine("Connect to Redis: " + connectionString);
            return true;
        }

        public static bool ConnectToXml(string connectionString)
        {
            Console.WriteLine("Connect to Xml: " + connectionString);
            return true;
        }
    }
internal class Program
    {
        private static void Main(string[] args)
        {
            var actionMap = new Dictionary>()
            {
                {DataSource.MySql, ConnectionDataHelper.ConnectToMySql},
                {DataSource.SqlServer, ConnectionDataHelper.ConnectToSqlServer},
                {DataSource.MongoDb, ConnectionDataHelper.ConnectToMongoDb},
                {DataSource.Redis, ConnectionDataHelper.ConnectToRedis},
                {DataSource.Xml, ConnectionDataHelper.ConnectToXml},
            };
            DataSource dataSource = DataSource.SqlServer;
            Console.WriteLine("Connection to DB Source: " + dataSource.ToString());
            var connectionString = "DataSource=; UserId=; Password=";
            bool isConnected = false;
            if (actionMap.ContainsKey(dataSource))
            {
                isConnected = actionMap[dataSource](connectionString);
            }
            Console.WriteLine("Is Connected" + isConnected);
            Console.ReadKey();
        }

        private enum DataSource
        {
            MySql,
            SqlServer,
            MongoDb,
            Redis,
            Xml
        }
    }

Kết quả:

Chúc các bạn thành công.