Запрос на проектирование программного обеспечения / архитектуру

#oop #design-patterns #architecture

#ооп #шаблоны проектирования #архитектура

Вопрос:

В книге «Шаблоны архитектуры корпоративных приложений» указано следующее:

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

С другой стороны, в книге «Гибкие принципы, шаблоны и практики» о принципе инверсии зависимостей говорится следующее:

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

Это меня как бы смущает. Я смешиваю здесь две разные вещи?

Ответ №1:

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

В первую очередь рассмотрим этот пример — в простой многоуровневой архитектуре у вас может быть уровень представления, построенный на JavaScript, уровень бизнес-логики, построенный на Java, и уровень данных в SQL Server. Эти уровни могут быть разработаны разными командами людей. Уровень представления знает, как выполнять вызовы API на уровне бизнес-логики, но не наоборот. Уровень бизнес-логики знает, как читать / записывать на уровень базы данных и из него, но не наоборот. Различие здесь происходит на высоком уровне — вы могли бы даже назвать это концептуальным.

Во втором случае вы хотите предотвратить сценарии, в которых предположительно общий код зависит от конкретных реализаций — и на данный момент я рассматриваю это как проблему относительно низкого уровня, которая подпадает под область применения конкретного приложения (т. Е. в коде, а не концептуально, как в предыдущем примере). Если у вас есть код, который выполняет запись в базу данных, но вы хотите поддерживать разные реализации — например, MySQL и SQL Server, где каждая из них может иметь некоторые специфические сложности, не заставляйте вызывающий код явно зависеть ни от одной из них — абстрагируйтесь от сложности через интерфейс. Это то, что решает принцип инверсии зависимостей (см. Ниже).

     public class UserService {

        public UserRepository repository;

        public void setUserRepository(UserRepository repository) {
           this.repository = repository;  //Is this a MySqlRepository or a SqlServerRepository?  We don't care - the dependency is managed outside and we can change it without changing this class.
        }

        public void persistUser() {
            this.repository.persist(user);  //We just care about the abstraction - the interface.
        }
    }
  

Ответ №2:

Я смешиваю здесь две разные вещи?

ДА.

В первом случае речь идет о зависимостях во время выполнения, а во втором случае речь идет о зависимостях во время компиляции.

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