>  기사  >  웹 프론트엔드  >  객체지향 자바스크립트 2부(인터페이스 구현 입문)_js 객체지향

객체지향 자바스크립트 2부(인터페이스 구현 입문)_js 객체지향

WBOY
WBOY원래의
2016-05-16 17:56:43902검색

객체지향 분야에서 인터페이스가 얼마나 중요한지 보여주는 것만으로도 충분합니다. 그러나 JS에는 다른 고급 객체 지향 언어(C#, Java, C 등)와 같이 한 객체 세트가 다른 객체 세트와 유사한 특성을 포함하는지 확인하는 내장 인터페이스 메커니즘이 없습니다. 다행스럽게도 JS는 유연성이 뛰어나므로(위에서 언급한) 인터페이스 기능을 매우 간단하게 모방할 수 있습니다. 그렇다면 인터페이스란 정확히 무엇일까요?

인터페이스는 동작이 유사한 일부 클래스(동일한 유형일 수도 있고 다른 유형일 수 있음) 간에 통일된 메소드 정의를 제공하므로 이러한 클래스가 원활하게 통신할 수 있습니다.

인터페이스를 사용하면 어떤 이점이 있나요? 간단히 말해서 시스템에서 유사한 모듈의 재사용성을 향상시키고 다양한 유형의 통신을 더욱 강력하게 만들 수 있습니다. 인터페이스가 구현되면 인터페이스의 모든 메소드를 구현해야 합니다. 대규모 웹 프로젝트의 경우 유사한 기능 모듈을 가진 여러 개의 복잡한 모듈은 서로 영향을 주지 않고 구현을 제공하기 위한 인터페이스만 제공하면 됩니다. 그러나 인터페이스가 전능하지 않다는 점을 분명히 해야 합니다. JS는 약한 유형의 언어이기 때문에 다른 팀 구성원이 제공하는 인터페이스를 엄격하게 따르도록 강요할 수는 없지만 코드 사양과 보조 클래스를 사용하면 이 문제를 완화할 수 있습니다. 또한 이는 시스템 요구 사항의 복잡성에 따라 결정되어야 하는 시스템 성능에도 일정한 영향을 미칩니다. 내장된 인터페이스가 없고 키워드를 구현하므로 JS가 인터페이스를 어떻게 모방하고 구현하는지 살펴보겠습니다.

1. 인터페이스를 구현하는 가장 간단하면서도 가장 효과적인 방법은 주석을 사용하는 것입니다. 즉, 주석에 인터페이스를 사용하여 인터페이스의 의도를 설명합니다.

코드 복사 코드는 다음과 같습니다.

/*
interface Composite {
function add(child);
function getChild(index);
}
interface FormItem {
function save(); >*/
var CompositeForm = function(id, name, action) {
// Composite, FormItem 구현
}
CompositeForm.prototype = {
// Composite 인터페이스 구현
추가: 함수(하위) {
//...
},
제거: 함수(하위) {
//...
},
getChild: 함수( index) {
//...
}
// FormItem 인터페이스 구현
save: function() {
//...
}
}


이것은 인터페이스의 기능을 시뮬레이션하고 Composite 클래스가 실제로 메소드 세트를 구현하는지 확인하는 데 효과적이지 않습니다. 프로그래머에게 문제를 알리기 위해 오류가 발생하지 않습니다. 설명 외에는 효과가 없습니다. 모든 일관성은 프로그래머가 자발적으로 수행합니다. 하지만 구현이 쉽고, 추가 클래스나 함수가 필요하지 않으며, 문서의 크기와 실행 속도에 영향을 주지 않으며, 주석을 쉽게 제거할 수 있어 제공되는 클래스에 대한 설명을 통해 어느 정도 재사용성이 향상됩니다. 다른 구현과 동일해야 합니다. 인터페이스 클래스가 통신합니다.
2. 모의 인터페이스를 속성으로 확인합니다. 클래스는 구현하려는 인터페이스를 명시적으로 선언하고, 속성을 통해 해당 인터페이스가 구현되었는지 확인합니다.



interface Composite {
function add(child);
function getChild(index);
}
interface FormItem {
function save(); >*/
var CompositeForm = function(id, name, action) {
this.implementsInterfaces = ["Composite", "FormItem"]
//...
}
function checkInterfaces( formInstance) {
if(!implements(formInstance, "Composite", "FormItem")) {
throw new Error("객체가 필요한 인터페이스를 구현하지 않습니다.")
}
/ /...
}
//인스턴스 객체가 필요한 인터페이스를 구현한다고 선언하는지 확인합니다.
function Implements(instance) {
for(var i = 1; i < 인수 .length; i ) {
var 인터페이스 이름 = 인수[i];
var isFound = false
for(var j = 0; j if(interfaceName == 인스턴스.implementsInterfaces[j]) {
isFound = true;
break;
}
}
if(!isFound) return false;// 인터페이스를 찾을 수 없습니다.
}
return true;// 모든 인터페이스를 찾았습니다.


여기에는 인터페이스를 설명하기 위해 주석이 추가되어 있습니다. 그러나 클래스가 구현해야 하는 인터페이스를 나타내기 위해 ImplementsInterfaces 속성이 Composite 클래스에 추가됩니다. 해당 인터페이스가 구현되었는지 확인하려면 이 속성을 확인하세요. 구현되지 않은 경우 오류가 발생합니다. 그러나 단점은 해당 인터페이스 메소드가 실제로 구현되었는지 여부를 여전히 판단할 수 없다는 점입니다. 인터페이스를 구현했다고 "주장"하기만 하면 해당 작업 부하도 증가합니다.

3. "오리 패턴 인식"을 사용하여 인터페이스를 구현합니다. 클래스가 속성 검사 구현에서 구현된 인터페이스를 지원하는지 여부는 중요하지 않습니다. 인터페이스의 모든 메서드가 클래스의 해당 위치에 표시되기만 하면 인터페이스가 구현되었음을 나타내는 것으로 충분합니다. 마치 "오리처럼 걷고 오리처럼 꽥꽥거린다면, 오리라고 적힌 라벨이 있든 없든 우리는 그것이 오리라고 생각합니다."와 같은 것입니다. 해당 인터페이스에 클래스가 존재(구현)하는지 여부를 확인하기 위해 보조 클래스를 사용한다. 존재하지 않는다면 구현되지 않았다는 뜻이다.
코드 복사 코드는 다음과 같습니다.

// 인터페이스
var Composite = new Interface( "Composite", ["add", "remove", "getChild"]);
var FormItem = new Interface("FormItem", ["save"])

var CompositeForm = function( id, name, action) {
// Composite, FormItem 인터페이스 구현
}
function checkInterfaces(formInstance) {
Interface.ensureImplements(formInstance, "Composite", "FormItem") ;
//...
}

인터페이스 클래스
코드 복사 코드는 다음과 같습니다.

// 인터페이스 클래스는 인스턴스 객체가 필요한 인터페이스의 모든 메소드를 구현하는지 확인하기 위한 클래스입니다.
var Interface = function(name,methods) {
if( args.length != 2 ) {
throw new Error("인터페이스 생성자는 2개의 인수를 기대하지만 "args.length" 인수에 대해 정확히 제공됩니다.")
this.name = name; 🎜>this.methods = [];
for(var i = 0;i if(typeofmethods[i] != "string") {
throw new Error("인터페이스 생성자는 문자열 메서드 이름을 전달해야 합니다.");
}
this.methods.push(methods[i])
}
}
//static class method
Interface .ensureImplements = function(instance) {
if(arguments.length < 2) {
throw new Error("Function Interface.ensureImplements에서는 최소 2개의 인수가 필요하지만 정확하게 전달되었습니다." 인수.길이 " 인수. ");
}
for(var i = 1, len = 인수.길이; i < len; i ) {
var 인터페이스 = 인수[i]; >if(interface.constructor != Interface) {
throw new Error("Function Interface.ensureImplements에서는 최소한 2개의 인수가 인터페이스의 인스턴스가 될 것으로 예상합니다.");
}
for(var j = 0 , mLen = 인터페이스.메소드 .length; j < mLen; j ) {
var 메소드 = 인터페이스.메소드[j]
if(!instance[메소드] || typeof 인스턴스[메소드] != " function") {
throw new Error("Function Interface.ensureImplements: 객체가 "interface.name"을 구현하지 않습니다. " method "를 찾을 수 없습니다.");
}
}
}
}


엄격한 유형 검사가 항상 필요한 것은 아니며 위의 인터페이스 메커니즘은 일반적인 웹 프런트엔드 개발에서는 거의 사용되지 않습니다. 그러나 복잡한 시스템, 특히 유사한 모듈이 많은 시스템에 직면하면 인터페이스 지향 프로그래밍이 매우 중요해질 것입니다. 이는 JS의 유연성을 감소시키는 것처럼 보이지만 실제로는 동일한 인터페이스를 구현하는 객체를 전달하면 올바르게 구문 분석될 수 있기 때문에 클래스의 유연성을 향상시키고 클래스 간의 결합을 감소시킵니다. 그렇다면 언제 인터페이스를 사용하는 것이 적절한가요? 대규모 프로젝트의 경우 팀원이 많아야 하며 프로젝트가 보다 세분화된 기능 모듈로 분할되어 진행을 보장하기 위해 사전에 "자리 표시자 프로그램"(인터페이스)을 사용하여 설명해야 합니다. 모듈의 기능이나 개발된 모듈과 연관되기 위해서는 완성된 모듈간 통신 시 통합 인터페이스(API)를 제공해야 합니다. 프로젝트가 계속 진행됨에 따라 요구 사항은 계속해서 변경될 수 있으며 그에 따라 각 모듈의 기능도 변경될 것입니다. 그러나 상위 모듈에 제공되는 API와 상호 간의 통신은 항상 변경되지 않아 안정성과 내구성이 보장됩니다. 전체 아키텍처의. 아래에서는 인터페이스의 실제 적용을 설명하기 위해 구체적인 예를 사용합니다. 클래스가 결과 객체(TestResult 클래스)를 자동으로 감지하고 인터페이스 구현을 사용하지 않고 웹 페이지 보기를 출력하도록 형식을 지정하도록 설계되었다고 가정합니다.


코드 복사 코드는 다음과 같습니다.

var ResultFormatter = function(resultObject) {
if(!(resultObject instanceof TestResult)) {
throw new Error("ResultFormatter 생성자는 TestResult의 인스턴스를 예상합니다.");
this.resultObject = resultObject;
}
ResultFormatter.prototype.render = function() {
var date = this.resultObject.getDate()
var items = this.resultObject. getResults();
var 컨테이너 = document.createElement("div");
var header = document.createElement("h3")

header.innerHTML = "" 날짜 .toUTCString();
container.appendChild(header);
var list = document.createElement("ul");
container.appendChild(list)

for(var i = 0, len = items.length; i ) {
var item = document.createElement("li")
item.innerHTML = items[i]
list.appendChild(item); 🎜>}
return 컨테이너;
}


우선 ResultFormatter 클래스의 생성자는 TestResult 인스턴스인지 여부만 확인하지만 getDate 메소드가 해당 인스턴스인지 여부는 보장하지 않습니다. ()가 렌더링되고 getResults()가 구현됩니다. 또한 요구 사항이 계속 변경됨에 따라 이제 getDate() 및 getResults() 메서드를 포함하는 Weather 클래스가 있지만 TestResult의 인스턴스인지 여부만 확인할 수 있기 때문에 render 메서드를 실행할 수 없습니다. 말이 너무 없네? 해결책은 수표 인스턴스를 제거하고 인터페이스로 교체하는 것입니다.


//ResultSet 인터페이스 생성
var ResultSet = new Interface("ResultSet", ["getDate", "getResults"]);
var ResultFormatter = function(resultObject) {
// Interface.ensureImplements를 사용하여 resultObject 확인
인터페이스. verifyImplements(resultObject , ResultSet);
this.resultObject = resultObject;
}
ResultFormatter.prototype.render = function() {
// 이전과 동일하게 유지
var date = this .resultObject.getDate();
var items = this.resultObject.getResults();
var 컨테이너 = document.createElement("div")
var header = document.createElement("h3") ;

header.innerHTML = "date.toUTCString()"의 테스트 결과
container.appendChild(header)
var list = document.createElement("ul"); 컨테이너.appendChild(목록);

for(var i = 0, len = items.length; i ) {
var item = document.createElement("li")
item.innerHTML = items[ i];
list.appendChild(item);
}
return 컨테이너
}


렌더링 방법이 변경되지 않은 것을 볼 수 있습니다. 어떤 식으로든. 변경된 것은 인터페이스를 추가하고 유형 확인을 위해 인터페이스를 사용하는 것뿐이었습니다. 동시에 이제 Weather 클래스의 인스턴스를 전달하여 호출할 수 있습니다. 물론 ResultSet 인터페이스를 구현하는 모든 클래스의 인스턴스를 전달하여 검사를 더욱 정확하고 관대하게 만들 수도 있습니다. 이후 JS 디자인 패턴이 도입되면서 인터페이스는 팩토리 모드, 조합 모드, 데코레이션 모드 및 명령 모드에서 널리 사용됩니다. 인터페이스가 JS 모듈식 디자인에 가져오는 이점을 모두가 즐길 수 있기를 바랍니다.
성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.