Принцип единой ответственности гласит, что каждый класс должен отвечать за одну конкретную вещь, должна быть только одна причина для изменения класса.

Это самый важный принцип SOLID, благодаря ему у нас не будет классов монстров после 2000 строк, которые будут отвечать за все, а будет много маленьких классов, отвечающих за разные части программы .

Большие классы всегда сложнее поддерживать, развивать и рефакторить, построение больших классов всегда рано или поздно приводит к таким проблемам, что если наш проект будет классом и будет отвечать за все, то в дальнейшем расширение этого класса, изменение его функционала тоже будет затрагивают совершенно разные области этого класса, что в больших проектах приводит к тому, что их просто невозможно расширять и модифицировать.

Однако, создавая множество небольших классов, вы повышаете читабельность, легкость расширения и, вообще говоря, простоту управления кодом проекта.

Перейдем к практическим примерам, примером класса, нарушающего принцип единой ответственности, является приведенный во введении:

class Products
{
     public List<string> ProductsInBag { get; set; }
     public int NumberProductsInShop { get; set; }
     public int NumberClientsInShop { get; set; }
     public List<string> TypesProductsInBag { get; set; }
     public int NumberOrders { get; set; }
     public string FirstNameClient { get; set; }
     public string LastNameClient { get; set; }
     public string ZipCodeClient { get; set; }
     public int NumberProductsInBag { get; set; }
     public int NumberDrinksInBag { get; set; }
     public int NumberCandysInBag { get; set; }
     public double PriceAllProductsInBag { get; set; }
 
     public Products(int numberproductsinShop)
     {
         NumberProductsInShop = numberproductsinShop;
     }
 
     public void IfClientWentToShop()
     {
         NumberClientsInShop += 1;
     }
 
     public string AddProduct(double priceproduct, string product, string typeproduct)
     {
        ProductsInBag.Add(product);
        if (TypesProductsInBag.Contains(typeproduct))
        {
            Console.WriteLine("This type of product is already in the cart!");
        }
        else
        {
            TypesProductsInBag.Add(typeproduct);
        }
 
        if (typeproduct == "candys")
        {
            NumberCandysInBag += 1;
        }
        else if (typeproduct=="drink")
        {
            NumberDrinksInBag += 1;
        }
           
        PriceAllProductsInBag += priceproduct;
        return product;
     }
 
     public string GiveOrders(string firstnameclient, string lastnameclient, string zipcodeclient)
     {
        NumberOrders += 1;
        FirstNameClient = firstnameclient;
        LastNameClient = lastnameclient;
        ZipCodeClient = zipcodeclient;
 
        NumberProductsInBag = ProductsInBag.Count;
 
        return "Order placed!";
     }
 
     public double BuyProducts(double mywallet)
     {
        return mywallet - PriceAllProductsInBag;
     }
}

Что у нас тут… Класс Products, который отвечает за все, за размещение заказов, клиентов, расчет товаров, добавление товаров, количество переменных вверху класса тоже не выглядит заманчиво, я забыл упомянуть, что принцип единой ответственности применяется не только к классам, но и к методам, так что один или несколько методов не делают все, вы также должны стараться делать самые короткие методы, желательно только выполнять одну операцию.

И у нас есть несколько методов, которые делают все. Если бы нам нужно было сделать практический проект, мы не могли бы оставить его таким, он должен выглядеть так:

namespace SingleResponsibility
{
    class Product
    {
        public void PriceProduct(double price)
        {
            Console.WriteLine("This product costs: " + price);
        }
    }
    class Client
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string ZipCode { get; set; }
        private double _myWallet;
        public double MyWallet { get => _myWallet; set => _myWallet = value; }
        public Client(string firstname, string lastname, string zipcode, double myWallet)
        {
            FirstName= firstname;
            LastName = lastname;
            ZipCode = zipcode;
            _myWallet = myWallet;
        }
    }
    class Shop
    {
        public int NumberProducts { get; set; }
        public int NumberClient { get; set; }
        public Shop(int numberproducts)
        {
            NumberProducts = numberproducts;
        }
        public void NewClient()
        {
            NumberClient += 1;
        }
    }
    class ClientCart
    {
        public List<string> Products { get; set; }
        public List<string> TypesProducts { get; set; }
        public int NumberProducts { get; set; }
        public int NumberDrinks { get; set; }
        public int NumberCandys { get; set; }
        public double PriceAllProducts { get; set; }
        public void SaveTypeProducts(string typeproduct)
        {
            if (TypesProducts.Contains(typeproduct))
            {
                Console.WriteLine("This type of product is already in the cart!");
            }
            else
            {
                TypesProducts.Add(typeproduct);
            }
            CheckTypeProducts(typeproduct);
        }
        private void CheckTypeProducts(string typeproduct)
        {
            if (typeproduct == "candys")
            {
                GetCandysCount();
            }
            else if (typeproduct == "drink")
            {
                GetDrinksCount();
            }
        }
        private void GetCandysCount()
        {
            NumberCandys += 1;
        }
        private void GetDrinksCount()
        {
            NumberDrinks += 1;
        }
        public double SumProductsPrice(double priceproduct)
        {
            return PriceAllProducts += priceproduct;
        }
        public int GetProductsCount()
        {
            return NumberProducts = Products.Count;
        }
        public void AddProduct(string product)
        {
            Products.Add(product);
        }
    }
    class Order
    {
        public int NumberOrder { get; set; }
        public void AddOrder()
        {
            NumberOrder += 1;
        }
        public string GiveOrder()
        {
            return "Order placed!";
        }
    }
}

И не лучше ли это выглядит? У нас есть конкретные классы и методы, отвечающие за конкретную часть логики магазина, код стал намного читабельнее, проще для понимания и модификации, также мы улучшили названия классов и методов. Конечно, вы, вероятно, можете улучшить что-то в каждом коде, независимо от того, насколько хорошо он был бы написан, насколько легко его было бы читать, если бы были соблюдены все правила программирования, не только SOLID, вы всегда можно что-то улучшить.

Но вы согласитесь, что это гораздо лучшее решение, чем то, в котором не применяется принцип единой ответственности.

А под вызовом функции Main:

namespace SingleResponsibility
{
    class Program
    {
        static void Main(string[] args)
        {
            double MyWallet = 30;
            Client client = new Client("Slawomir", "Kowalski", "81-198", MyWallet);
            ClientCart clientCart = new ClientCart();
            clientCart.Products = new List<string>();
            clientCart.TypesProducts = new List<string>();
            Shop shop = new Shop(100);
            shop.NewClient();
            clientCart.AddProduct("cola");
            clientCart.SaveTypeProducts("drink");
            clientCart.SumProductsPrice(5.6);
            clientCart.AddProduct("sprite");
            clientCart.SaveTypeProducts("drink");
            clientCart.SumProductsPrice(3.5);
            clientCart.AddProduct("candy");
            clientCart.SaveTypeProducts("candys");
            clientCart.SumProductsPrice(1.4);
            Order order = new Order();
            Console.WriteLine(order.GiveOrder() +
               "\nThe number of products in the cart: " +                  clientCart.GetProductsCount() +
               "\nOrder placed by: " + client.FirstName + " " +               client.LastName
               + "\nNumber of drinks in the cart: " +  clientCart.NumberDrinks
               + "\nThe number of sweets in the cart: " +  clientCart.NumberCandys
               + "\nPrice of all products: " +  clientCart.PriceAllProducts);
            Console.WriteLine("It's in my wallet: " +  (client.MyWallet - clientCart.PriceAllProducts) + " PLN");
            Console.ReadKey();
        }
    }
}

Результат:

Резюме

На следующем уроке, как вы, наверное, догадались, будет обсуждаться принцип SOLID, открыто-закрыто.

Ссылка на github со всем кодом из этой статьи: https://github.com/Slaw145/SingleResponsibility

Этот контент также можно найти в моем блоге steemit https://steemit.com/solid/@slawas/solid-principles-1-single-responsibility-principle

И в моем блоге devman:http://devman.pl/programtech/solid-principles-1-single-responsibility-principle/

Стандартно напоминаю о бюллетене, в котором рассылаю уведомления о новых записях и дополнительную информацию о мире ИТ в целом.

И ОБЯЗАТЕЛЬНО присоединяйтесь к сообществу DevmanCommunity на фб, часть сообщества находится в одном месте

– сайт на фб: Devman.pl-Славомир Ковальски

— группа на фб: DevmanCommunity

Спрашивайте, комментируйте в конце поста, делитесь им, оценивайте, делайте что хотите.