Sobes.tech
Middle+
122
questionbank

Что такое принципы SOLID?

Ответ от нейросети

sobes.tech AI

SOLID — это набор из пяти основных принципов объектно-ориентированного проектирования, направленных на создание расширяемых, понятных и легко поддерживаемых систем.

  1. Single Responsibility Principle (Принцип единственной ответственности): Каждый класс должен иметь только одну причину для изменения. Это означает, что класс должен выполнять только одну четко определенную задачу.

    // Нарушение SRP
    public class Report
    {
        public void GenerateReport() { /* ... */ }
        public void SaveToFile(string filename) { /* ... */ }
    }
    
    // Соблюдение SRP
    public class ReportGenerator
    {
        public void GenerateReport() { /* ... */ }
    }
    
    public class ReportSaver
    {
        public void SaveToFile(string filename) { /* ... */ }
    }
    
  2. Open/Closed Principle (Принцип открытости/закрытости): Программные сущности (классы, модули, функции и т. д.) должны быть открыты для расширения, но закрыты для модификации. Это достигается с помощью абстракций (интерфейсов, абстрактных классов).

    // Нарушение OCP
    public class AreaCalculator
    {
        public double CalculateArea(object shape)
        {
            if (shape is Rectangle r)
            {
                return r.Width * r.Height;
            }
            else if (shape is Circle c)
            {
                return Math.PI * c.Radius * c.Radius;
            }
            // придется изменять класс при добавлении новой фигуры
            return 0;
        }
    }
    
    // Соблюдение OCP
    public interface IShape
    {
        double CalculateArea();
    }
    
    public class Rectangle : IShape
    {
        public double Width { get; set; }
        public double Height { get; set; }
        public double CalculateArea() { return Width * Height; }
    }
    
    public class Circle : IShape
    {
        public double Radius { get; set; }
        public double CalculateArea() { return Math.PI * Radius * Radius; }
    }
    
    public class NewAreaCalculator
    {
        public double CalculateArea(IShape shape)
        {
            return shape.CalculateArea(); // можно добавлять новые фигуры, не меняя этот класс
        }
    }
    
  3. Liskov Substitution Principle (Принцип подстановки Лисков): Подтипы должны быть заменяемы своими базовыми типами без нарушения работоспособности программы. Это означает, что производный класс должен полностью соответствовать контракту своего базового класса.

    // Нарушение LSP
    public class Rectangle
    {
        public virtual int Width { get; set; }
        public virtual int Height { get; set; }
    }
    
    public class Square : Rectangle
    {
        public override int Width
        {
            get { return base.Width; }
            set { base.Width = base.Height = value; } // Нарушается контракт Rectangle
        }
    
        public override int Height
        {
            get { return base.Height; }
            set { base.Width = base.Height = value; } // Нарушается контракт Rectangle
        }
    }
    
    // Соблюдение LSP (может потребоваться перепроектирование иерархии)
    // Или использовать фабричный метод для создания правильных типов
    
  4. Interface Segregation Principle (Принцип разделения интерфейсов): Клиентам не следует зависеть от интерфейсов, которые они не используют. Большие монолитные интерфейсы следует разделять на более мелкие и специфические.

    // Нарушение ISP
    public interface IMultiFunctionPrinter
    {
        void Print(string document);
        void Scan(string document);
        void Fax(string document);
    }
    
    public class SimplePrinter : IMultiFunctionPrinter
    {
        public void Print(string document) { /* ... */ }
        public void Scan(string document) { throw new System.NotImplementedException(); } // Не нужно сканирование
        public void Fax(string document) { throw new System.NotImplementedException(); } // Не нужен факс
    }
    
    // Соблюдение ISP
    public interface IPrinter
    {
        void Print(string document);
    }
    
    public interface IScanner
    {
        void Scan(string document);
    }
    
    public interface IFax
    {
        void Fax(string document);
    }
    
    public class NewSimplePrinter : IPrinter
    {
        public void Print(string document) { /* ... */ }
    }
    
  5. Dependency Inversion Principle (Принцип инверсии зависимостей):

    • Модули верхних уровней не должны зависеть от модулей нижних уровней. Оба типа модулей должны зависеть от абстракций.
    • Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.
    // Нарушение DIP
    public class LightBulb
    {
        public void TurnOn() { /* ... */ }
        public void TurnOff() { /* ... */ }
    }
    
    public class ElectricPowerSwitch
    {
        private LightBulb bulb;
    
        public ElectricPowerSwitch(LightBulb bulb)
        {
            this.bulb = bulb; // Прямая зависимость от конкретной реализации LightBulb
        }
    
        public void Press()
        {
            // ...
        }
    }
    
    // Соблюдение DIP
    public interface ISwitchable
    {
        void TurnOn();
        void TurnOff();
    }
    
    public class NewLightBulb : ISwitchable
    {
        public void TurnOn() { /* ... */ }
        public void TurnOff() { /* ... */ }
    }
    
    public class NewElectricPowerSwitch
    {
        private ISwitchable device;
    
        public NewElectricPowerSwitch(ISwitchable device)
        {
            this.device = device; // Зависимость от абстракции ISwitchable
        }
    
        public void Press()
        {
            // ...
        }
    }