JavaScript design pattern-interface implementation

Source: Internet
Author: User

JavaScript design pattern-interface implementation

1. Interface
(1) What is an interface?
An interface provides a means to describe the methods that an object should have. Although it can indicate the semantics of these methods, it does not specify how these methods should be implemented. For example, if an interface contains a method named setName, you have reason to think that the implementation of this method should have a string parameter and assign this parameter to a name variable. With this tool, you can group objects based on their features. For example, even if a batch of objects are significantly different from each other and they all implement the Comparable interface, these objects can be used interchangeably in the object. compare (anotherObject) method. You can also use interfaces to develop commonalities between different classes. If you change a function that originally requires a specific class as a parameter to a function that requires a specific interface as a parameter, any object that implements this interface can be passed as a parameter. In this way, irrelevant objects can be treated equally.
(2) benefits of interfaces
In object-oriented javascript, what is the function of interfaces? A set of established interfaces are self-descriptive and can promote code reuse. The interface can tell programmers which methods are implemented by a class to help them use this class. If you are familiar with a specific interface, you already know how to use any class that implements it, so that you are more likely to reuse the existing class. The interface also helps to stabilize the communication methods before different classes. If you know the interface in advance, you can reduce the problems encountered during the integration of two objects. With it, you can explain in advance what features and operations you want a class to have. A program can define an interface for the required class and forward it to another program. The second programmer can write his own code as he wishes, as long as the class he defines implements that interface. This is especially useful in large projects. It is particularly useful in large projects.
Testing and debugging can also be easier. In a weak javascript language, it is difficult to track Type Mismatch Errors. Using Interfaces makes it easier to find such errors, because if an object is not of the required type or there is no necessary method to implement it, then you will get a clear error message containing useful information. In this way, logical errors can be restricted to methods rather than object structures. The interface also makes the code more stable, because any changes to the interface must be reflected in all classes that implement it. If an operation is added to an interface and a class implementing it does not add the operation, you will see an error immediately.
(3) interface disadvantages
The interface has no disadvantages. Javascript is a language with strong image performance, mainly thanks to its weak type features. The use of interfaces strengthens the role of types in a certain program. This reduces the language flexibility.
Javascript does not provide built-in support for interfaces, but there is always a risk of trying to imitate the built-in functions of other languages. Javascript does not have the keyword "interface". Therefore, no matter what method you use to implement interfaces, it is always very different from the methods in C ++ and java. This increases the difficulty encountered when javascript is first involved.
Any method that implements an interface in javascript may have some performance impact. In a program, this is attributed to the overhead of additional method calls. In our implementation method, two for loops are used to traverse each method in each required interface. For large interfaces and objects that need to implement many different interfaces, this check may take some time to negatively affect the performance. If you care about this problem, you can remove the code after the required code is enabled, or associate the execution with a debugging flag so that it will be executed in the operating environment. But be sure not to optimize it too early. Performance Analyzer such as firebug can help you determine whether it is really necessary to remove interface code.
The biggest problem with using interfaces in js is that it is impossible for other programmers to comply with your defined interfaces. In other languages, the interface concept is built-in. If someone defines a class that implements an interface, the compiler will ensure that the class does implement this interface. In javascript, you must manually implement an interface for a class. Coding specifications and helper classes can provide some help, but this problem cannot be completely eliminated. If other programmers in the project do not take interfaces seriously, the use of these interfaces cannot be guaranteed. Unless the project owner agrees to use the interface and checks it, many values of the interface will not be reflected.

2. Simulate interfaces in javascript
The following three methods can be used to simulate an interface in javascript:
1. Description
2. Attribute Check Method
3. Duck Pattern Recognition
No technology is perfect, but the combination of the three is basically satisfactory.
Use comments to describe interfaces
Imitating interfaces with comments is the simplest method, but the effect is the worst. This method imitates the practices in other Page Object languages and uses the interface and implements keywords, but puts them in comments to avoid syntax errors. As follows:

<Script> // There are three methods for defining interfaces in javascript: // 1. annotation description/*** interface Composite {* function add (obj ); * function remove (obj); * function update (obj);} advantages: programmers can have reference disadvantages: There are many disadvantages. It is just an excuse for document category, if you do not implement all the methods, the program can still run, too loose. * // Implement of interface Composite var CompositeImpl = function () {/* this. add = function (obj) {}; this. remove = function (obj) {}; this function-defined method will generate a new method when instantiating an object, and each method of strength is different. So use the following method: */CompositeImpl. prototype. add = function (obj) {} CompositeImpl. prototype. remove = function (obj) {} CompositeImpl. prototype. update = function (obj) {}} var c1 = new CompositeImpl (); var c2 = new CompositeImpl () alert (c1.add = c2.add) // 2. Attribute detection // 3. Duck identification </script>

2. Property Detection
This method is more rigorous. All classes explicitly declare the interfaces they implement, and objects that want to deal with these classes may check these declarations. The interfaces are still comments, but now you can check an attribute to find out what interfaces a class claims to implement.
This kind of imitation is not very good. It does not check to ensure that CompositeForm implements the correct method set, nor throws errors to inform programmers of problems in the program. In the end, it mainly belongs to the scope of program documents. In this way, the compliance with the interface conventions is completely self-conscious.
However, this method also has its advantages. It is easy to implement and does not require additional classes or functions. It can improve the reusability of code, because the interfaces implemented by those classes are explained, and programmers can use them with other classes that implement the same interface. This method does not affect the file size or execution speed, because the comments it uses can be removed from the image without any charges when deploying the code. However, since no error message is provided, it does not help in testing and debugging.

<Script>/*** interface Composite {* function add (obj); * function remove (obj); * function update (obj ); *} * interface FormItem {* function select (obj); *} * // CompositeImpl implements interface Composite, FormItem var CompositeImpl = function () {// displayed inside the class, an excuse for receiving implementation. Generally, this is a specification. // Our Project Manager: defines an array for the internal class and the name must be fixed. this. interfaceImplments = ['composite ', 'formitem']; CompositeImpl. prototype. add = function (o Bj) {alert (xiaopingguo);} CompositeImpl. prototype. remove = function (obj) {} CompositeImpl. prototype. update = function (obj) {}/* CompositeImpl. prototype. select = function (obj) {}* // defines the function detection to determine whether the current object has implemented all the functions checkCompositeImpl (instance) {if (! IsImplments (instance, 'composite ', 'formitem') {throw new Error ('object cannot implements all the interface ');};} // common detection methods (core methods). The main purpose is to determine whether the sample object has implemented related interfaces. function isImplments (object) {// actual function object of the arguments object for (var I = 1, len = arguments. length; I <len; I ++) {// receives the name var interfaceName = arguments [I] for implementing each interface; // determines whether the method is implemented or failed? InterfaceImplments. var interfaceFound = false; for (var j = 0; j

In this example, CompositeForm declares that it has implemented the Composite and FormItem interfaces. The method is to add these two interface names to an array named implementsInterfaces. Class explicitly declares what interfaces are supported. Any function that requires a specific type of parameter can check this attribute and throw an error when the required interface does not declare the column.
This method has several advantages. It provides instructions on the interfaces implemented by the class. If the required interface is not included in the list of interfaces that the class declares to support, you will see an error message. By using these errors, you can force other programmers to declare these interfaces.
The main drawback of this method is that it does not ensure that the class actually implements the self-implemented interface. You only know whether the interface is implemented by yourself. When creating a class, declare that it implements an interface, but then it misses one of the methods specified by this interface. This error is common. At this time, all the checks can pass, but the method does not exist, which will bury a hidden danger in the code. In addition, it takes some additional work to explicitly declare the interfaces supported by the class.

3. Duck identification Interface
In fact, it is not important for a class to declare which interfaces it supports, as long as it has methods in these interfaces. Duck-style model (this name comes from James Whitomb Riley's famous saying: "walking like a duck and screaming as a duck") is based on this understanding. It sets the method set implemented by the object as the unique criterion for judging whether it is an instance of a class. This technology can be used to check whether a class has implemented an interface. The idea behind this method is simple: if an object has all the methods with the same name as the method defined by the interface, it can be considered as implementing this interface. You can use an auxiliary function to ensure that the object has all the necessary methods:

<Script>/* The third method for implementing interfaces: Duck-style identifying and implementing interfaces. (perfect implementation method) core idea: the main purpose of a class to implement interfaces: all of these methods are implemented (detection methods) and fully object-oriented code is unified, implement decoupling * // 1. Interface Class --- Class Interface ==> instantiate parameters of multiple interfaces/*** Interface classes? Several * parameter 1: Interface name * parameter 2: Set of receiving methods (array) */var Interface = function (name, methods) {// determine the number of parameters of the interface if (arguments. length! = 2) {throw new Error ('the instance interface constructor arguments shocould be 2');}; this. name = name; // this. methods = methods; this. methods = []; for (var I = 0, len = methods. length; I

Unlike the other two methods, this method does not use annotations. All of these aspects can be enforced. The ensureImplements function requires at least two parameters. The first parameter is the object to be checked. Other parameters are interfaces for checking the object. This function checks whether the object represented by the first parameter implements all the methods declared by those interfaces. If any method is missing, it will throw an error, which contains useful information such as the missing method and the name of the interface that is not correctly implemented. This check can be used in any code where an object needs to implement an interface. In this example, the addForm function adds a form object only when it supports all necessary methods.
Although duck pattern recognition may be the most useful of the three methods above, it also has some disadvantages. In this method, the class does not declare the interfaces implemented by itself, which reduces the reusability of the code and lacks the self-descriptive methods of the other two methods. It requires an auxiliary class Interface and an auxiliary function ensureImplements. Besides, it only cares about the method name and does not check the parameter name, number, or type.

4. Combination of 1st and 3rd
We use annotations to declare interfaces supported by the class, so as to improve code reusability and the perfection of the document. We also use the auxiliary class Interface and class method Interface. ensureImplements to check the display of the methods implemented by the object. If the object fails to pass the check, a useful error message is returned for this request.

It can be seen that all methods of this class have strict requirements on their parameters. If the parameter fails to pass the check, it will cause an error to be thrown. The purpose of this check is: If no error is thrown, you can be sure that the interface has been correctly declared and implemented.
5. Use Cases of Interface classes
Strict type checks are not always wise. Many js programmers do not have to use interfaces or the checks it provides, and they have been working for years. When using the design pattern to implement a complex system, an interface can best reflect its value. It seems to reduce the flexibility of javascript, but in fact, because the use of interfaces can reduce the coupling between objects, it improves the flexibility of code. The interface can make the function more flexible, because you can pass any type of parameters to the function and ensure that it only uses the objects with the necessary methods.
Interface Class usage
It is the most important step to determine whether the interface is cost-effective in the code. The benefits of interfaces may not be obvious for small and less troublesome projects, but they only increase complexity. You need to weigh the advantages and disadvantages on your own. If you think that the advantages and disadvantages of using interfaces in projects are greater than the disadvantages, you can refer to the following instructions:
1. Add the Interface class to an HTML file.
2. Check all methods in the Code with objects as parameters one by one. Find out the methods required by the normal operation of the Code for these object parameters
3. Create an Interface object for every different method set you need.
4. Remove all explicit checks for constructors. Because we use a duck-like pattern, the object type is no longer important.
5. Replace the original constructor check with Interface. ensureImplements.
Example
Suppose you want to create a class, which can convert some automated test results into formats suitable for viewing on the web page. The constructor of this class takes the instance of a TestResult class as the parameter. It will format and output the data encapsulated by the TestResult object at the customer's request.
Original Definition:

 var ResultFormatter =function(resultsObject){        if(!(resultsObject instanceof TestResult)){            throw newError(ResultsFormatter:constructor requires an instance of TestResult asan argument.)        }        this.resultsObject = resultsObject;    }    ResultFormatter.prototype.renderResults =function(){        var dateOfTest = this.resultsObject.getDate();        var resultsArray =this.resultsObject.getResults();        var resultsContainer =document.createElement('div');        var resultsHeader =document.createElement(h3);        resultsHeader.innerHTML = TestResults from +dateOfTest.toUTCString();        resultsContainer.appendChild(resultsHeader);        var resultList =document.createElement(ul);       resultsContainer.appendChild(resultList);        for(var i=0,len=resultsArray.length;i
      

The constructor of this class checks the parameters to ensure that they are indeed instances of the TestResult class. If the parameter cannot be displayed, the constructor throws an error. With this guarantee, when writing the renderResults method, you can determine that the getDate and getResults methods are available. In fact, this does not guarantee that the required methods are implemented. The TestResult class may be modified, so that it no longer has the getDate () method. In this case, the check in the constructor can still pass, but the renderResults method fails.
In addition, this check of the constructor imposes some unnecessary restrictions. It does not allow instances of other classes to be used as parameters, even if they could have been used as intended. For example, a method named WeatherData also has the getDate and getResults methods. It can be used well by the ResultFormatter class. However, the explicit type check will prevent any instances that use the WeatherData class.
The solution is to delete the check using instanceOf and replace it with an interface. First, we need to create this interface:
// ResultSetInterface.
Var ResultSet = new Interface ("ResultSet", ['getdate', 'getresult']);
The code above creates a new instance of the Interface object. The first parameter is the interface name, and the second parameter is a string array. Each string is a required method name. With this interface, you can use the Interface Check to replace the instanceOf check.
Var ResultFormatter = function (resultsObject ){
Interface. ensureImplements (resultsObject, ResultSet );
This. resultsObject = resultsObject;
}
ResultFormatter. prototype. renderResults = function (){
...
}
The renderResults method remains unchanged. The constructor uses the ensureImplements method instead of the instanceof operator. The constructor can now accept instances of WeatherData or any other classes required for implementation. We only modified several lines of the ResultFormatter class code to make the check more accurate and tolerant.

6. Interface-dependent Design Mode
L factory Model
L Combination Mode
L decoration Mode
L command mode

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.