머리말
이 장에서는 LSP (종속성 반전 원칙) 인 견고한 JavaScript 언어의 5 가지 주요 원칙을 구현 한 다섯 번째 장을 설명 할 것입니다.
오리지널 영어 텍스트 : http://freshbrewedcode.com/derekgreeer/2012/01/22/solid-javaScript--dependency-inversion-principle/
의존 반전 원리
의존성 반전 원리에 대한 설명은 다음과 같습니다.
A. 높은 수준의 모듈은 저수준 모듈에 의존해서는 안됩니다. 둘 다 추상화에 의존해야합니다.
높은 수준 모듈은 저수준 모듈에 의존해서는 안되며 둘 다 추상화에 의존해야합니다.
B. 추상화는 세부 사항에 의존해서는 안됩니다. 세부 사항은 추상화에 따라야합니다.
초록은 세부 사항에 의존해서는 안되며 세부 사항은 추상화에 의존해야합니다.
의존성 반전 원칙의 가장 중요한 문제는 응용 프로그램 또는 프레임 워크의 주요 구성 요소가 중요하지 않은 기본 구성 요소의 구현 세부 사항에서 분리되도록하는 것입니다. 이는 프로그램의 가장 중요한 부분이 저수준 구성 요소의 변경 및 수정에 의해 영향을받지 않도록합니다.
이 원칙의 첫 번째 부분은 높은 수준 모듈과 저수준 모듈 간의 결합에 관한 것입니다. 전통적인 디비전 아키텍처에서 고급 모듈 (프로그램의 핵심 비즈니스 논리를 캡슐화)은 항상 일부 저수준 모듈 (일부 기본 포인트)에 의존합니다. 의존성 반전의 원리가 적용되면 관계가 역전됩니다. 저수준 모듈에 의존하는 고급 모듈과 달리 종속성 반전은 저수준 모듈이 높은 수준 모듈로 정의 된 인터페이스에 의존하게 만듭니다. 예를 들어, 프로그램에 대한 데이터를 지속하려면 기존 디자인은 핵심 모듈이 영구 모듈의 API에 따라 다르다는 것입니다. 의존성 반전 원칙에 따른 재구성 후, 핵심 모듈은 지속적인 API 인터페이스를 정의해야하며, 지속적인 구현 인스턴스는 코어 모듈에 의해 정의 된 API 인터페이스를 구현해야합니다.
이 원칙의 두 번째 부분은 추상화와 세부 사항 사이의 올바른 관계를 설명합니다. C ++ 언어를 이해 함으로써이 부분을 이해하는 것이 도움이됩니다. 적용 가능성이 더 분명하기 때문입니다.
정적으로 입력 한 일부 언어와 달리 C ++는 인터페이스를 정의하는 언어 수준의 개념을 제공하지 않습니다. 클래스 정의와 클래스 구현의 관계는 무엇입니까? C ++에서 클래스는 헤더 파일 형태로 정의되며,이 파일은 클래스 멤버 메소드와 소스 파일이 구현 해야하는 변수를 정의합니다. 모든 변수와 개인 메소드는 헤더 파일에 정의되므로 구현 세부 정보 전에 추상화 및 분리하는 데 사용될 수 있습니다. 인터페이스의 개념은 추상 방법 (C ++의 추상 기본 클래스) 만 정의하여 구현하여 클래스를 구현하는 데 사용됩니다.
딥 및 JavaScript
JavaScript는 역동적 인 언어이기 때문에 분리를 위해 추상화 할 필요가 없습니다. 따라서 추상화는 세부 사항에 의존해서는 안됩니다. 이 변경은 JavaScript에 큰 영향을 미치지 않지만 높은 수준의 모듈은 저수준 모듈에 의존해서는 안되지만 큰 영향을 미칩니다.
정적으로 입력 된 언어의 맥락에서 의존성 반전 원리를 논의 할 때, 커플 링의 개념에는 의미 론적 및 물리적이 포함됩니다. 즉, 높은 수준의 모듈이 저수준 모듈에 의존하는 경우 의미 론적 인터페이스뿐만 아니라 기본 모듈에 정의 된 물리적 인터페이스도 커플 링됩니다. 다시 말해, 높은 수준의 모듈은 타사 라이브러리뿐만 아니라 기본 저수준 모듈에서 분리되어야합니다.
이를 설명하기 위해 .NET 프로그램에는 저수준 영구 모듈에 의존하는 매우 유용한 고급 모듈이 포함되어 있다고 상상해보십시오. 저자가 Persistence API와 유사한 인터페이스를 추가 해야하는 경우, 종속성 반전 원칙이 사용되는지 여부에 관계 없이이 저수준 모듈의 새로운 인터페이스를 다시 구현하기 전에 다른 프로그램에서 고급 모듈을 재사용 할 수 없습니다.
JavaScript에서, 의존성 반전 원칙의 적용 가능성은 고급 모듈과 저수준 모듈 사이의 의미 론적 커플 링으로 제한됩니다. 예를 들어 DIP는 저수준 모듈로 정의 된 암시 적 인터페이스를 결합하는 대신 필요에 따라 인터페이스를 추가 할 수 있습니다.
이를 이해하려면 다음 예를 살펴 보겠습니다.
코드 사본은 다음과 같습니다.
$ .fn.trackmap = 함수 (옵션) {
var defaults = {
/ * 기본값 */
};
옵션 = $ .extend ({}, 기본값, 옵션);
var mapoptions = {
센터 : New Google.maps.latlng (옵션. latitude, 옵션 .longitude),
줌 : 12,
MapTypeid : google.maps.maptypeid.roadmap
},
map = new Google.maps.map (this [0], MapPoptions),
pos = new google.maps.latlng (옵션. latitude, 옵션 .longitude);
var 마커 = 새로운 Google.maps.marker ({
위치 : POS,
제목 : 옵션, 테이틀,
아이콘 : Options.icon
});
Marker.setMap (맵);
옵션 .feed.update (함수 (위도, 경도) {
Marker.setMap (null);
var newlatlng = new Google.maps.latlng (위도, 경도);
Marker.Position = newlatlng;
Marker.setMap (맵);
map.setCenter (newlatlng);
});
이것을 반환하십시오;
};
var updater = (function () {
// 개인 속성
반품 {
업데이트 : 기능 (콜백) {
updatemap = 콜백;
}
};
}) ();
$ ( "#map_canvas"). TrackMap ({{
위도 : 35.044640193770725,
경도 : -89.98193264007568,
아이콘 : 'http://bit.ly/zjngde',
제목 : '추적 번호 : 12345',
피드 : 업데이트
});
위의 코드에는 DIV를 맵으로 변환하여 현재 추적 된 위치 정보를 표시하는 작은 JS 클래스 라이브러리가 있습니다. TrackMap 함수에는 2 개의 종속성이 있습니다 : 타사 Google Maps API 및 위치 피드. 피드 객체의 책임은 아이콘 위치가 업데이트 될 때 콜백 콜백 (초기화에서 제공)을 호출하고 위도 위도 및 정밀도로 전달하는 것입니다. Google Maps API는 인터페이스 렌더링에 사용됩니다.
피드 객체의 인터페이스는 설치를 기반으로하거나 설치 트랙 맵 함수의 요구 사항에 따라 설계되지 않았을 수 있습니다. 실제로, 그 역할은 간단한 다른 구현에 중점을두고 Google지도에 크게 의존 할 필요가 없습니다. 트랙 맵 시맨틱은 Google Maps API와 결합됩니다. 다른 맵 제공 업체로 전환 해야하는 경우 다른 제공 업체에 적응할 수 있도록 트랙 맵 함수를 다시 작성해야합니다.
Google Maps 클래스 라이브러리의 의미 론적 커플 링을 뒤집으려면 Design Trackmap 함수를 암시 적 인터페이스 (MAP 제공 업체 제공 업체의 인터페이스 초록)에 시맨틱 커플 링에 다시 작성해야합니다. 또한 Google Maps API에 조정 된 구현 객체도 필요합니다. 다음은 리팩토링 된 트랙 맵 함수입니다.
코드 사본은 다음과 같습니다.
$ .fn.trackmap = 함수 (옵션) {
var defaults = {
/ * 기본값 */
};
옵션 = $ .extend ({}, 기본값, 옵션);
옵션 .provider.showmap (
이 [0],
옵션.
옵션.
Options.icon,
옵션. 타이틀);
옵션 .feed.update (함수 (위도, 경도) {
옵션 .provider.updatemap (위도, 경도);
});
이것을 반환하십시오;
};
$ ( "#map_canvas"). TrackMap ({{
위도 : 35.044640193770725,
경도 : -89.98193264007568,
아이콘 : 'http://bit.ly/zjngde',
제목 : '추적 번호 : 12345',
피드 : 업데이트,
제공자 : trackmap.googlemapsprovider
});
이 버전에서는 TrackMap 함수와 필요한 맵 제공자 인터페이스를 다시 디자인 한 다음 구현 세부 정보를 별도의 GoogleMapsprovider 구성 요소로 옮겼으며 독립적으로 별도의 JavaScript 모듈로 캡슐화 될 수 있습니다. GoogleMapsprovider 구현은 다음과 같습니다.
코드 사본은 다음과 같습니다.
trackmap.googlemapsprovider = (function () {
var 마커,지도;
반품 {
showmap : 함수 (요소, 위도, 경도, 아이콘, 제목) {
var mapoptions = {
센터 : New Google.maps.latlng (위도, 경도),
줌 : 12,
MapTypeid : google.maps.maptypeid.roadmap
},
pos = new Google.maps.latlng (위도, 경도);
map = new Google.maps.map (요소,지도);
마커 = 새로운 Google.maps.marker ({
위치 : POS,
제목 : 제목,
아이콘 : 아이콘
});
Marker.setMap (맵);
},
updatemap : 함수 (위도, 경도) {
Marker.setMap (null);
var newlatlng = new Google.maps.latlng (위도, 경도);
Marker.Position = newlatlng;
Marker.setMap (맵);
map.setCenter (newlatlng);
}
};
}) ();
위의 변경을 한 후 트랙 맵 함수는 매우 유연 해지고 Google Maps API에 의존 할 필요가 없습니다. 대신, 다른 MAP 제공 업체를 마음대로 교체 할 수 있습니다. 즉, 모든지도 제공 업체는 프로그램의 요구에 따라 조정할 수 있습니다.
종속성 주입은 언제입니까?
약간 관련이 없습니다. 실제로, 의존성 주입의 개념은 종종 의존성 반전의 원리와 혼합된다. 이 차이를 명확히하기 위해서는 다음과 같이 설명해야합니다.
의존성 주입은 특별한 형태의 제어 역전이며, 반전은 구성 요소가 종속성을 얻는 방법을 의미합니다. 종속성 주입은 다음을 의미합니다. 종속성은 종속성을 얻기 위해 구성 요소가 아닌 구성 요소에 제공됩니다. 즉, 종속성의 인스턴스를 생성하고, 공장을 통한 종속성을 요청하고, 서비스 로케이터 또는 구성 요소 자체를 통한 종속성을 요청합니다. 의존성 반전 원리 및 의존성 주입은 모두 종속성에 중점을두고 반전에 사용됩니다. 그러나 의존성 반전의 원리는 구성 요소가 종속성을 얻는 방법에 초점을 맞추지 않고, 높은 수준의 모듈이 저수준 모듈에서 분리되는 방법에만 초점을 맞추고 있습니다. 어떤 의미에서, 의존성 반전의 원리는 또 다른 형태의 제어 역전이다. 여기서, 반전은 모듈이 인터페이스를 정의하는 것입니다 (하위 레벨에서 정의, 역전으로의 역전).
요약
이것은 5 가지 주요 원칙의 마지막 기사입니다. 이 5 개의 기사에서는 JavaScript에서 Solid가 어떻게 구현되는지 알 수 있습니다. 다른 원리는 자바 스크립트의 다른 각도에서 설명됩니다. (Uncle Note : 사실, 나는 그것이 약간 부적절하지만 다른 관점에서 볼 때 일반적인 원칙은 실제로 다양한 언어에서 동일하다고 생각합니다.)