Classes should depend on abstractions, not on concrete details.

Let’s see example. We have report forms class, that can connect to database and do some queries. If you don’t know patterns, you can write something like that:

        public class Report
        {
            public void Run()
            {
                MySqlDb db = new MySqlDb();
                db.Open();
                string[,] res = db.ExecuteQuery("select...");
                db.Close();
            }
        }

        public class MySqlDb 
        {
            public void Open()
            {

            }
            public void Close()
            {

            }
            public string[,] ExecuteQuery(string query)
            {
                string[,] res = new string[1, 1];
                return res;
            }
        }

This code has report class and mysql class. If we will need connect to other database (for example Postgres), we will have to rewrite client code.

What we can do to avoid rewriting code? At least, we can pick out interface IDb, that will have several methods for different database types.

        public class Report
        {
            public void Run()
            {
                IDb db = new MySqlDb();
                db.Open();
                string[,] res = db.ExecuteQuery("select...");
                db.Close();
            }
        }

        public class MySqlDb :IDb
        {
            public void Open()
            {

            }
            public void Close()
            {

            }
            public string[,] ExecuteQuery(string query)
            {
                string[,] res = new string[1, 1];
                return res;
            }
        }

        public interface IDb
        {
            public void Open();
            public void Close();
            public string[,] ExecuteQuery(string query);
        }

Now we can easily add several database types support.