Is enough to show how important an interface is in an object-oriented domain. But JS does not have built-in interface mechanisms like other object-oriented high-level languages (c#,java,c++, etc.) to determine that a group of objects and another group of objects contain similar characteristics. Fortunately, JS has a lot of flexibility (I've talked about it earlier), which makes it easy to mimic interface features. So what is the interface?
interface, providing a uniform method definition between classes that have similar behavior, possibly the same type, or different types, so that communication can be implemented well between these classes.
What are the benefits of using interfaces? Simply put, it can improve the reusability of similar modules, and make the communication of different classes more stable. Once the interface is implemented, all the methods in the interface must be implemented. For large Web projects, the similar functional modules of multiple complex modules need only provide an interface to provide an implementation that is unaffected by each other. But we have to be clear, interface is not omnipotent, because JS is a weak type language, you can not force other team members to strictly follow the interface you provide, but you can use code specifications and helper classes to alleviate this problem. In addition, the system performance will also have a certain impact, depending on the complexity of your systems requirements. As there is no built-in interface and implements keywords, let's look at how JS simulates the implementation of the interface.
1. The simplest and least effective way to implement an interface is to use annotations. That is, use interface in the annotation to illustrate the intent of the interface.
Copy Code code as follows:
/*
Interface Composite {
function add (child);
function remove (child);
function Getchild (index);
}
Interface Formitem {
Funtion Save ();
}
*/
var compositeform = function (ID, name, action) {
Implements Composite, Formitem
}
Compositeform.prototype = {
Implements composite interface
Add:function (Child) {
//...
},
Remove:function (Child) {
//...
},
Getchild:function (index) {
//...
}
Implements Formitem interface
Save:function () {
//...
}
}
This does not have a good interface to simulate the functionality and ensure that the composite class does implement a collection of methods, and does not throw errors to notify the programmer of the problem, in addition to the description does not play any role, all the consistency requires the programmer to complete consciously. However, it is easy to implement, does not require additional classes or functions, does not affect the size of the document and the speed of execution, annotations can be easily stripped, and to some extent increased reusability, because the description of the class can communicate with other classes that implement the same interface.
2. Check the analog interface with attributes. Class displays the interface that is declared to be implemented, and whether the corresponding interface is implemented through a property check.
Copy Code code as follows:
/*
Interface Composite {
function add (child);
function remove (child);
function Getchild (index);
}
Interface Formitem {
Funtion Save ();
}
*/
var compositeform = function (ID, name, action) {
This.implementsinterfaces = ["Composite", "Formitem"];
//...
}
function Checkinterfaces (forminstance) {
if (!implements (forminstance, "composite", "Formitem")) {
throw new Error ("Object doesn ' t implement required interface.");
}
//...
}
Check to the If a instance object declares that it implements the required interface
function implements (instance) {
for (var i = 1; i < arguments.length; i++) {
var InterfaceName = arguments[i];
var isfound = false;
for (var j = 0; J < Instance.implementsInterfaces.length; J + +) {
if (InterfaceName = = Instance.implementsinterfaces[j]) {
Isfound = true;
Break
}
}
if (!isfound) return false;//A interface is not found.
}
Return true;//all interfaces were found.
}
As found here, annotations are still added to illustrate the interface. However, a property implementsinterfaces is added to the composite class, stating that the class must implement those interfaces. By examining the property to determine whether the appropriate interface is implemented, an error is thrown if it is not implemented. But the disadvantage is that you still can't tell whether the interface method is really implemented, just "claiming" to implement the interface, but also increase the corresponding workload.
3. Use "Duck type" to realize the interface. It does not matter whether a class supports the implemented interface from the property check implementation, as long as all the methods in the interface appear in the corresponding place in the class, which is sufficient to indicate that the interface has already been implemented. It's like, "If you walk like a duck, like a duck quack, whether it's labeled as a duck or not, then we think it's a duck." Use the helper class to determine whether a class exists (implements) all the methods in the corresponding interface, and if not, the representative is not implemented.
Copy Code code as follows:
Interfaces
var composite = new Interface ("Composite", ["Add", "Remove", "getchild"]);
var formitem = new Interface ("Formitem", ["Save"]);
var compositeform = function (ID, name, action) {
Implements composite, Formitem interfaces
}
function Checkinterfaces (forminstance) {
Interface.ensureimplements (Forminstance, "composite", "Formitem");
//...
}
Interface class
Copy Code code as follows:
Interface class is for checking if a instance object implements all methods of required Interface
var Interface = function (name, methods) {
if (arguments.length!= 2) {
throw new Error ("Interface constructor expects 2 arguments, but exactly provided for" + Arguments.length + "arguments." );
}
THIS.name = name;
This.methods = [];
for (var i = 0;i < Methods.length; i++) {
if (typeof Methods[i]!= "string") {
throw new Error ("Interface constructor expects to pass a string method name.");
}
This.methods.push (Methods[i]);
}
}
Static Class method
Interface.ensureimplements = function (instance) {
if (Arguments.length < 2) {
throw new Error ("Function Interface.ensureimplements expects at least 2 arguments, but exactly for" + passed Ngth + "arguments.");
}
for (var i = 1, len = Arguments.length i < len; i++) {
var interface = Arguments[i];
if (Interface.constructor!= interface) {
throw new Error ("Function Interface.ensureimplements expects at least 2 arguments to is instances of Interface.");
}
for (var j = 0, Mlen = interface.methods.length J < Mlen; J + +) {
var method = Interface.methods[j];
if (!instance[method] | | typeof Instance[method]!= "function") {
throw new Error ("Function Interface.ensureImplements:object doesn" t implements "+ Interface.name +". Method "+ method +" wasn ' t found. ");
}
}
}
}
Strict type checking is not always necessary, and the above interface mechanism is rarely used in the usual web front-end development. But when you're faced with a complex system that has many similar modules in particular, interface programming becomes very important. Seems to reduce the flexibility of JS, in essence, improve the flexibility of classes, reduce the degree of coupling between classes, because when you pass into any object that implements the same interface can be correctly parsed. When is the right time to use the interface is more appropriate? For a large project, there must be a lot of team members, and the project will be split into finer-grained functional modules, providing a unified interface (API) is necessary in order to ensure that progress requires the use of "placeholder" (interface) to explain the function of the module or communicate with the developed modules. As the project progresses, there may be constant changes in demand and changes in the functionality of each module, but communication between each other and the API provided to the upper module remains unchanged to ensure the stability and durability of the entire architecture. Here's a concrete example to illustrate the actual application of the interface. Suppose you design a class to automatically detect the result object (TestResult Class) and format the output of a Web page view without using an interface implementation:
Copy Code code as follows:
var resultformatter = function (resultobject) {
if (!) ( Resultobject instanceof TestResult)) {
throw new Error ("Resultformatter Constructor expects a instance of TestResult.");
}
This.resultobject = Resultobject;
}
ResultFormatter.prototype.render = function () {
var date = This.resultObject.getDate ();
var items = This.resultObject.getResults ();
var container = document.createelement ("div");
var header = document.createelement ("h3");
header.innerhtml = "Test result from" + date.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 container;
}
First, the constructor of the Resultformatter class simply checks whether it is a testresult instance, but it is not guaranteed to implement the method GetDate () and GetResults () in render. In addition, with the constant change in demand, there is now a weather class, including the GETDATE () and GetResults () method, but because can only check whether it is an instance of TestResult can not run the Render method, it is very silent? The solution is to remove the instanceof check and replace it with an interface.
Copy Code code as follows:
Create the ResultSet interface
var ResultSet = new Interface ("ResultSet", ["GetDate", "GetResults"]);
var resultformatter = function (resultobject) {
Using interface.ensureimplements to check the Resultobject
Interface.ensureimplements (Resultobject, ResultSet);
This.resultobject = Resultobject;
}
ResultFormatter.prototype.render = function () {
Keep the same as former
var date = This.resultObject.getDate ();
var items = This.resultObject.getResults ();
var container = document.createelement ("div");
var header = document.createelement ("h3");
header.innerhtml = "Test result from" + date.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 container;
}
You can see that the render method has not changed anything. The only change is to add an interface and use an interface for type checking. It is also now possible to pass an instance of the weather class to make the call, and of course to pass an instance of any class that implements the ResultSet interface, making the inspection more precise and tolerant. With the subsequent introduction of JS design mode, the interface will be widely used in Factory mode, combination mode, decoration mode and command mode. I hope you can savor the interface to our JS Modular design benefits.