Рубрики
Без рубрики

Понимание твердых принципов: инверсия зависимости

Это 1-я часть серии понимания твердых принципов, где мы исследуем то, что такое инверсия зависимости, и почему она помогает предоставить программное обеспечение, которое слабо связано и реализовано

Автор оригинала: Theofanis Despoudis.

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

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

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

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

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

В Твердое Существует пять основных принципов, которые помогают создать хорошую (или твердую) архитектуру программного обеспечения. Твердое – это аббревиатура, где: –

  • S обозначает SRP (Принцип одной ответственности)
  • O обозначает OCP (Открытый закрытый принцип)
  • Л обозначает Lsp (Принцип замены Лиска)
  • Я стоять за ISP (Принцип сегрегации интерфейса)
  • D обозначает Dip (Принцип инверсии зависимости)

Первоначально составлен Роберт С. Мартин Вернувшись в 1990-х годах, эти принципы предоставляют способ построить компоненты программного обеспечения, которые плотно связаны с бесперебойным кодом с плохой сплоченностью и небольшими инкапсуляцией к полной противоположности; Свободно связанный код, сплоченные и действительно инкапсулирующие реальные потребности бизнеса соответствующим образом.

Хорошая практика a_nything, что _REDUCES муфты, что улучшает оправдание, ремонтопригодность и умение.

Темазависимость

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

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

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

Для оставшихся этой статьи я начну исследую Принцип инверсии зависимости.

Инверсия зависимости.

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

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

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

С другой стороны, у вас есть Модули низкого уровня или детали. Это наоборот. Это программы, написанные для решения конкретной проблемы. Их объем ограничен и часто охватывает единицу или подсистему. Например, открытие соединения базы данных MySQL считается низким уровнем, что и его привязанность к определенному объему.

Теперь, читая эти 2 правила, что вы можете подразумевать?

Реальное намерение за инверсией зависимости является Отделение Объекты в той степени, в которой ни один клиентский код не должен быть изменен, просто потому, что объект зависит от необходимости изменяться на другой. Что достигает свободно муфта Поскольку каждый из его компонентов имеет или использовать, мало или нет знания о определениях других отдельных компонентов. Это достигает Жилье и заменяемость Поскольку компоненты в свободной связанной системе могут быть заменены альтернативными реализациями, которые обеспечивают те же услуги.

Недостаток инверсии зависимости заключается в том, что вам нужно Зависимость инверсионный контейнер И вам нужно настроить его. Этот контейнер будет иметь необходимые возможности ввести ваши услуги в необходимых местах с правильной областью и правильными параметрами.

Большой! Так как начать?

Мы можем узнать больше о инверсии зависимости, на практике, используя потрясающую библиотеку в JavaScript под названием Interfify.js Отказ

Interfify.js. Мощное и легкое инверсию управления контейнерами для JavaScript & Node.js, работающих на TypeScript.

В этом примере я покажу вам, как предоставлять услуги для Websocket связь.

Скажем, например, у вас есть. Вот несколько решений для предоставления простого веб-сайта. Есть Socket.io , Носки , простой Websocket и т. Д. И у каждого из них есть разные API или разные методы, которые вы можете позвонить. Было бы здорово, если бы мы как-то абстрагировали всю идею поставщика Websocket в общем интерфейсе? Таким образом, мы можем предоставить другой создатель Websocket в зависимости от наших потребностей.

Во-первых, давайте определим наши интерфейсы:

export interface WebSocketConfiguration { uri: string; options?: Object;}

export interface SocketFactory { 
  createSocket(configuration: WebSocketConfiguration): any;
}

Обратите внимание, что здесь нет ничего конкретного, просто интерфейсы. Мы говорим, что это наше Абстракции.

Теперь, давайте скажем, мы хотим, что мы хотим розетка-IO:

import {Manager} from 'socket.io-client';

class SocketIOFactory implements SocketFactory { 
 	createSocket(configuration: WebSocketConfiguration): any { 
    	return new Manager(configuration.uri, configuration.opts); 
    }
}

Это что-то конкретное и больше не абстрактно, потому что он указывает Менеджер от библиотеки Socket-io. Это наше Детали Отказ

Мы могли бы добавить еще много заводских классов, пока они реализуют Сокетография интерфейс.

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

Давайте снова начнем с новой абстракцией:

export interface SocketClient { 
  connect(configuration: WebSocketConfiguration): Promise; 
  close(): Promise; 
    emit(event: string, ...args: any[]): Promise; 
    on(event: string, fn: Function): Promise;
}

Давайте предоставляем подробный вид нашей абстракции:

class WebSocketClient implements SocketClient { 
  private socketFactory: SocketFactory; 
    private socket: any;

  public constructor(webSocketFactory: SocketFactory) { 
    	this.socketFactory = webSocketFactory; 
    }

  public connect(config: WebSocketConfiguration): Promise { 
    	if (!this.socket) { 
        	this.socket = this.socketFactory.createSocket(config); 
    	}

    return new Promise((resolve, reject) => { 
        	this.socket.on('connect', () => resolve()); 				this.socket.on('connect_error', (error: Error) => reject(error)); 
        }); 
    }

  public emit(event: string, ...args: any[]): Promise { 
    	return new Promise((resolve, reject) => { 
        	if (!this.socket) { return reject('No socket connection.');}
      return this.socket.emit(event, args, (response: any) => { 
        		if (response.error) { return reject(response.error);}
        return resolve(); 
        	}); 
   		}); 
    }

  public on(event: string, fn: Function): Promise { 
    	return new Promise((resolve, reject) => { 
        	if (!this.socket) { return reject('No socket connection.'); }
      this.socket.on(event, fn); 
        	resolve(); 
        }); 
    }
    
  public close(): Promise { 
    	return new Promise((resolve) => { 
        	this.socket.close(() => { 
            	this.socket = null; resolve(); 
            }); 
        }); 
    }
}

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

Вот где инверсификация приходит и управляет таким контролем. Давайте добавим некоторые аннотации в смесь:

import {injectable} from 'inversify';

const webSocketFactoryType: symbol = Symbol('WebSocketFactory');
const webSocketClientType: symbol = Symbol('WebSocketClient');

let TYPES: any = { 
  WebSocketFactory: webSocketFactoryType, 
  WebSocketClient: webSocketClientType
};

@injectable()
class SocketIOFactory implements SocketFactory {...}
...
@injectable()
class WebSocketClient implements SocketClient {

  public constructor(@inject(TYPES.WebSocketFactory) webSocketFactory: SocketFactory) { 
    this.socketFactory = webSocketFactory;
  }
}

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

import {Container} from 'inversify';
import 'reflect-metadata';
import {TYPES, SocketClient, SocketFactory, SocketIOFactory, WebSocketClient} from '@web/app';

const provider = new Container({defaultScope: 'Singleton'});

// Bindings
provider.bind(TYPES.WebSocketClient).to(WebSocketClient);
provider.bind(TYPES.WebSocketFactory).to(SocketIOFactory);
export default provider;

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

var socketClient = provider.get(TYPES.WebSocketClient);

Конечно, Intervify предлагает больше, чем простые привязки. Я предлагаю вам голову над Сайт и проверить это.

Упражнения

  1. Найдите, какие другие существуют другие библиотеки, которые обеспечивают контейнер инверсии зависимости.
  2. В примерах я создал создание контейнера с использованием «Singleton». Что произойдет, если я не уточню это? Какой еще один способ сделать это, используя инверсию?
  3. Посмотрите на свои собственные проекты или веб-сайты и подумайте о том, как вы можете использовать инверсию зависимости от ваших услуг. Пример API звонков, обещания и т. Д.
  4. Дополнительные кредиты: Реализуйте свою собственную дистанционную библиотеку. Иметь класс или структуру данных, которая принимает ключи и значения. Для ключей вы указываете имя и значение, которые вы указываете, вырешил экземпляр. Попробуйте добавить методы уточнения области применения как синглтон или как завод.

Реконструировать

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

Рекомендации

Подойдя к следующему понимает солидные принципы: ответственность за единую ответственность

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

Счастливое кодирование.

Прочитайте оригинальную статью здесь