/** * 接口是一种指定对象应该有哪些方法的技术,他不关心方法如何实现。 * 基于接口编程的好处是:实现相同接口的对象,可以互换,而不影响功能实现。 * 接口还有利于大项目中,多人合作的交流 */ /**************** 在js中模仿接口 ******************/ //用注释描述接口 //效果最差,不会提供错误信息 //易于实现 /* interface Composite { function add(child); function remove(child); function getChild(index); } interface FormItem { function save(); */ var CompositeForm = function (id, method, action) { //implements Composite, FormItem }; //implement the Composite interface CompositeForm.prototype.add = function (child) { }; CompositeForm.prototype.remove = function (child) { }; Composite.prototype.getChild = function (index) { }; //implement the formItem interface CompositeForm.prototype.save = function () { }; //用属性检查模仿接口 /* 优点: 对类所实现的接口提供了文档说明 如果没有必须的接口会提示错误消息 缺点: 显示声明类所支持的接口,但没有真正检测接口是否存在 */ /* interface COMposite { function add(child); function remove(child); function getChild(index); } interface FormItem { function save(); } */ var CompositeForm = function (id, method, action) { //add interface into array this.implementsInterfaces = ['Composite', 'FormItem']; //... }; function addForm(formInstance) { if (!implements(formInstance, 'Composite', 'formItem')) { throw new Error('Object does not implement a required interface.'); } //... } //The implement function,which checks to see if an object declares that //it implements the required interface function implements(object) { //looping through all arguments after the first one for (var i = 1; i < arguments.length; i++) { var interfaceName = arguments[i]; var interfaceFound = false; for (var j = 0; j < object.implementsInterfaces.length; j++) { if (object.implementsInterfaces[j] == interfaceName) { interfaceFound = true; break; } } if (!interfaceFound) { //an interface was not found return false; } } //all interface were found return true; } //用鸭式辩型模仿接口 //如果对象具有与接口定义的方法同名的所有方法 //那么就可以认为它实现了这个接口 /** * 三种方法中最有用的一种 * 缺点: * 类并不声明自己实现了那些接口,降低了代码的可重用性 * 缺乏自我描述 * 不检查方法的参数 */ //Interface. var Composite = new Interface('Composite', ['add', 'remove', 'getChild']); var FormItem = new Interface('FormItem', ['save']); //CompositeForm class var CompositeForm = function (id, method, action) { //... }; //... function addForm(formInstance) { ensureImplements(formInstance, Composite, FormItem); //this function will throw an error if a required method is not implemented //... } //本书采用的接口实现方法 //结合第一种和第三种方法 //interfaces var Composite = new Interface('Composite', ['add', 'remove', 'getChild']); var formItem = new Interface('FormItem', ['save']); //CompositeForm class var CompositeForm = function (id, method, action) { //... }; //... function addForm(formInstance) { Interface.ensureImplements(formInstance, Composite, FormItem); //this function will throw an error if a required method is not implemented //halting execution of the function //all code beneath this line will be executed only if the checks pass //... } /************ Interface类 *************/ //Constructor var Interface = function (name, method) { // 检测参数个数 if (arguments.length != 2) { throw new Error('Interface constructor called with ' + arguments.length + 'arguments,ut expected exactly 2.'); } this.name = name; this.methods = []; //遍历方法 for (var i = 0, len = method.length; i < len; i++) { //检查数组值是否字符串 //如果不是,抛出错误信息 if (typeof method[i] !== 'string') { throw new Error('Interface constructor expects method names to be passed in as a string'); } //将方法名添加到属性数组中 this.methods.push(method[i]); } }; //static class method Interface.ensureImplements = function (object) { //参数个数必须大于等于2个 if (arguments.length < 2) { throw new Error('Function Interface.ensureImplements called with ' + arguments.length + 'arguments,but expected at least 2.'); } //遍历除第一个参数的其他参数 for (var i = 1, len = arguments.length; i < len; i++) { var interface = arguments[i]; //如果不是Interface的实例,则抛出错误 if (interface.constructor !== Interface) { throw new Error('Function interface.ensureImplements expectes arguments two and above to be instances of Interface.'); } //遍历实例中的方法 for (var j = 0, methodsLen = interface.methods.length; j < methodsLen; j++) { var method = interface.methods[j]; //如果object没有实例中的方法,则抛出错误 if (!object[method] || typeof object[method] !== 'function') { throw new Error('Function Interface.ensureImplements:object does not implement the ' + interface.name + 'interface. Method ' + method + ' was not found.'); } } } }; //使用 var DynamicMap = new Interface('DybamicMap', ['centerOnPoint', 'zoom', 'draw']); function displayRoute(mapInstance) { Interface.ensureImplements(mapInstance, DynamicMap); mapInstance.centerOnPoint(12, 34); mapInstance.zoom(5); mapInstance.draw(); //... } var Test = function () { }; Test.prototype = { centerOnPoint:function (a, b) { console.log('centerOnPoint2'); }, zoom:function (num) { console.log('zoom2'); }, draw:function(){ } }; var a = new Test(); displayRoute(a); //实例 // ResultFormatter class,before we implement interface checking //未使用Interface类检测 var TestResult = function () { }; TestResult.prototype = { getDate:function () { }, getResults:function () { } }; var ResultFormatter = function (resultsObject) { // 是否为TestResult的实例 // 不是就抛出错误 if (!(resultsObject instanceof TestResult)) { throw new Error('ResultsFormatter: constructor requires an instance of TestResult as an 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 = 'Test Results from ' + dateOfTest.toUTCString(); resultsContainer.appendChild(resultsHeader); var resultsList = document.createElement('ul'); resultsContainer.appendChild(resultsList); for (var i = 0, len = resultsArray.length; i < len; i++) { var listItem = document.createElement('li'); listItem.innerHTML = resultsArray[i]; resultsList.appendChild(listItem); } //返回创建的DOM return resultsContainer; }; /* TestResult类可能被修改,致使其不再拥有getDate()方法 检查仍能通过,但renderResults方法却会失灵 不允许其他类的实例作为参数 */ //使用Interface类后 //ResultSet interface var ResultSet = new Interface('ResultSet', ['getDate', 'getResults']); //ResultFormatter class, after adding Interface checking var ResultFormatter = function (resultsObject) { Interface.ensureImplements(resultsObject, ResultSet); this.resultsObject = resultsObject; }; ResultFormatter.prototype.renderResults=function(){ //... };
本文参考链接:https://www.cnblogs.com/webFrontDev/archive/2012/12/16/2820374.html