Чтобы стать высокооплачиваемым разработчиком, вам нужно изучить TDD. По сути, вам нужно разрабатывать программное обеспечение с помощью TDD, чтобы попасть в крупную компанию. Если есть несколько концепций, которые вы должны знать перед тем, как приступить к TDD, это принцип инверсии зависимостей принципа SOLID, который вам следует знать. Начинающим разработчикам может быть нелегко это понять, но, к счастью, вы только что нашли самое простое руководство в мире. Я уверен, что этот краткий учебник будет большим подспорьем в вашей карьере.

*TDD: разработка через тестирование*

Что такое принцип инверсии зависимостей?

Принцип инверсии зависимостей соответствует D среди принципов SOLI’D’. Его принцип начинается с этого утверждения.

Модули высокого уровня не должны зависеть от модулей низкого уровня. Оба должны зависеть от абстракций.

Хорошо организованный код всегда имеет иерархию. Есть модули высокого уровня и модули низкого уровня. Но иногда разработчики-новички неправильно понимают эту концепцию и переносят низкоуровневые модули напрямую в высокоуровневые.

Вы видите, что не так с этим кодом?

import java.util.Arrays;
import java.util.List;
// High Level Module 
class ProductCatalog {

    public void listAllProducts() {

        SQLProductRepository sqlProductRepository = new SQLProductRepository();

        List<String> allProductNames = sqlProductRepository.getAllProductNames();

        // Display product names

    }

}
// Low Level Module 
class SQLProductRepository {

    public List<String> getAllProductNames() {
        return Arrays.asList("soap", "toothpaste", "shampoo");
    }

}

Что вы думаете? Вы видите проблему? Класс ProductCatalog является высокоуровневым модулем, но он зависит от своего подмодуля SQLProductRepository.

Это ошибка, которую часто допускают начинающие разработчики.

Позвольте мне повторить снова. Принцип инверсии зависимостей говорит

«Модули высокого уровня не должны зависеть от модулей низкого уровня. Оба должны зависеть от абстракций».

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

Теперь вы понимаете проблему. Тогда как это исправить? Прежде чем вы это исправите, давайте посмотрим, что означает abstraction в дизайне программного обеспечения.

Что такое Абстракция?

(1) Код без абстракции

class Benz  {

    public void drive() {
                
    }

}

class CarUtil {

    public static void drive(Benz benz) {
        benz.drive();
    }

}

Как видно из приведенного выше кода, метод статического привода класса CarUtil зависит от Benz. Вы должны предоставить экземпляр Benz, чтобы метод CarUtil drive() функционировал. В дизайне программного обеспечения это называется «сильной связью». Это также означает, что когда вы изменяете метод drive() внутри класса Benz, это напрямую влияет на CarUtil. Это склонно к ошибкам.

Сильная связь — самая нежелательная функция программного обеспечения

(2) Код с абстракцией

interface Car {
    public void drive();
}

class Benz implements Car {

    @Override
    public void drive() {
        
        
    }

}

class Tesla implements Car {

    @Override
    public void drive() {
        
    }

}

class CarUtil {

    public static void drive(Car car) {
        car.drive();
    }

}

Этот код выглядит идеально. Метод статического привода CarUtil не зависит от Benz, но зависит от интерфейса Car. Теперь он может принимать любой аргумент, реализующий Car Interface. Это называется абстракцией. Его также называют «слабая связь».

Теперь вернемся к предыдущему примеру кода.

Рефакторинг предыдущего кода с помощью абстракции

«Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций».

import java.util.Arrays;
import java.util.List;

// High Level Module 
class ProductCatalog {

    public void listAllProducts() {

        // High Level Module depends on Abstraction 
        ProductRepository productRepository =  new SQLProductRepository();

        List<String> allProductNames = productRepository.getAllProductNames();

        // Display product names

    }

}
interface ProductRepository {

    List<String> getAllProductNames();

}

// Low Level Module
class SQLProductRepository implements ProductRepository {

    public List<String> getAllProductNames() {
        return Arrays.asList("soap", "toothpaste", "shampoo");
    }

}

Теперь ProductCatalog зависит от ProductRepository вместо SQLProductRepository..

Зачем делать это снова?

Во-первых, вы не знаете, какую базу данных собираетесь использовать. Это может быть не конкретно SQL.

Во-вторых,ProductCatalog's listAllProducts() не зависит от конкретного объекта. Это означает, что когда вы изменяете код в SQLProductRepository, ProductCatalog не затрагивается напрямую. Вы только что достигли loose-coupling.

Что вы достигли сейчас

До рефакторинга ProductCatalog зависело от SQLProductRepository.

После рефакторинга ProductCatalog зависит от ProductRepository, а SQLProductRepository также зависит от ProductRepository.

Позвольте мне еще раз напомнить вам о принципе инверсии зависимостей.

«Модули высокого уровня не должны зависеть от модулей низкого уровня. Оба должны зависеть от абстракций».

Я думаю, вы теперь понимаете предложение полностью!

Шаг вперед, внедрение зависимостей

import java.util.Arrays;
import java.util.List;

class ProductCatalog {

    private ProductRepository productRepository;

    public ProductCatalog(ProductRepository productRepository) {
        this.productRepository = productRepository;
    }

    public void listAllProducts() {

        List<String> allProductNames = productRepository.getAllProductNames();

        // Display product names

    }

}

interface ProductRepository {

    List<String> getAllProductNames();

}

class SQLProductRepository implements ProductRepository {

    public List<String> getAllProductNames() {
        return Arrays.asList("soap", "toothpaste", "shampoo");
    }

}

class EcommerceApplication {
    
        public static void main(String[] args) {
            
            ProductRepository productRepository = new SQLProductRepository();

            ProductCatalog productCatalog = new ProductCatalog(productRepository);

            productCatalog.listAllProducts();
    
        }
    
}

Теперь вы вводите ProductRepository в ProductCatalog. Это обычная практика и даже рекомендуемый способ построения объектов. Вы поймете его полезность, когда изучите концепции Mock и TDD. Но если я объясню это сейчас, я не смогу сдержать обещание «Самое простое руководство в мире».

Заключение

  • «Модули высокого уровня не должны зависеть от модулей низкого уровня. Оба должны зависеть от абстракций».
  • «Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций».

Если вы можете понять эти два утверждения, вы полностью поняли принцип инверсии зависимостей! Поздравляем!

Но если нет, не волнуйтесь. Вы не сможете легко понять принцип инверсии зависимостей, если у вас нет опыта. Это также требует «преднамеренной практики».

Другие статьи для твердых принципов



Принцип единой ответственности: Что? работая «инженером-программистом, вы этого не знаете?!?!
Вы когда-нибудь сталкивались с тем, что рефакторинг кода не делает ваш код лучше? Добавление спагетти поверх спагетти…paigeshin1991.medium.com»