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

SOLID - это мнемотехническая аббревиатура, определенная Робертом К. Мартином (широко известным как дядя Боб) для пяти принципов проектирования, созданных для того, чтобы сделать проекты программного обеспечения более удобными, понятными и гибкими.

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

У нас есть много информации о них в Интернете, но меньше, когда вы пытаетесь применить их в javascript. С другой стороны, почти все примеры, которые я нашел, повторяют одни и те же случаи, и иногда их нелегко понять интуитивно.

Пять твердых принципов разработки программных приложений:

S - Принцип единой ответственности (SRP)
O - Принцип открытого / закрытого (OCP)
L - Принцип замещения Лискова (LSP)
I - Принцип разделения интерфейса (ISP)
D - Принцип инверсии зависимостей (DIP)

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

Принцип инверсии зависимостей

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

Основы этого принципа:

  • Модули высокого уровня не должны зависеть от модулей низкого уровня. Оба должны зависеть от абстракций.
  • Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.
  • DIP - это привязка классов к интерфейсам, потребляемым клиентским кодом.
  • DIP утверждает, что классы, реализующие интерфейсы, не видны клиентскому коду.

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

Есть несколько способов предоставить экземпляру необходимые зависимости, например:

  • Внедрение метода
  • Внедрение конструктора
  • Внедрение собственности

Но как реализовать DIP в JavaScript?

Другая реализация внедрения зависимостей в JavaScript - с модулями ES6 с возможностью использовать и инкапсулировать один и тот же код, а затем импортировать его туда, где он нам нужен.

В следующем примере у нас есть класс с именем DownloadToConsole. В этом классе у нас есть метод: downloadDataFromAPI, который загружает данные из внешнего API и затем записывает их в консоль. Но в чем проблема этой реализации? Что, если вместо Fetch мы захотим использовать другую форму для получения данных, например Axios или XMLHttpRequest?

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

Давайте посмотрим на пример:

DownloadToConsole.js

1. С помощью Fetch напрямую.

const url = "https://jsonplaceholder.typicode.com/posts"
class Example {
 constructor() {
  ...
 }
 downloadDataFromAPI(params) {
        
  //1.
  fetch(url, {
   method: 'GET'
  }).then(r => r.json())
    .then(r => {
      console.log("Posts:" + r);
   });
 }
}

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

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

Теперь создайте doGet метод в файле utils.js, чтобы инкапсулировать, как получить данные.

utils.js

2. Здесь мы можем использовать Fetch, Axios или XMLHttpRequest.

export const doGet = (url) => {
 //2.
 return fetch(url, {
        method: 'GET',
        mode: 'same-origin',
        ...
 }).then(r => r.json())
};

DownloadToConsole.js

Мы можем просто импортировать doGet зависимость и использовать ее:

import { doGet } from './utils.js'
const url = "https://jsonplaceholder.typicode.com/posts"
class Example{
 constructor() {
  ...
 }
 downloadDataFromAPI(params) {
       
  doGet(url)
   .then(r => {
    console.log("Posts:" + r);
   });
 }
}

Теперь вместо Fetch, если мы хотим использовать Axios, мы изменим только реализацию doGet в utils.js, чтобы использовать Axios, и все по-прежнему будет работать так же, как и раньше, без необходимости ничего больше изменять. .

utils.js

export const doGet = (url) => {
  return axios.get(url);
};

Вывод

Чтобы проиллюстрировать этот принцип, я максимально упростил его использование, экспортировав метод, в котором логика загрузки данных будет реализована с использованием Fetch, Axios или другим способом.

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

Кроме того, в нашем примере, инкапсулируя код, мы добились того, чтобы не повторяться. (Принцип СУХОЙ)

использованная литература



ТВЕРДЫЕ принципы:

Https://en.wikipedia.org/wiki/SOLID

Спасибо, что прочитали меня. Я надеюсь, что вы сочли полезным!

JavaScript на простом английском языке

Вы знали, что у нас четыре публикации? Найдите их всех на plainenglish.io - проявите немного любви, подписавшись на наши публикации и подписавшись на наш канал YouTube!