JavaScript 面向对象设计---接口

  接口在面向对象编程中是非常重要的概念/工具,早在四人帮(GOF)的Design Pattern 中提到面向对象编程的其中一规则是“面向接口编程,而不要面向实现编程”。--这可见接口在可复用的面向对象设计中的重要性吧~

    对于面向对象JavaScript而言,实现接口并不简单,因为JavaScript并没有内建支持接口。幸运的是,我们可以利用JavaScript的灵活性来模拟实现接口。在模拟接口前,首先了接一下其他面向对象如何定义/处理接口:

    1.Java

1  public   interface  DataOutput {
2  void  writeBoolean( boolean  value)  throws  IOException;
3  void  writeByte( int  value)  throws  IOException;
4  void  writeChar( int  value)  throws  IOException;
5  void  writeShort( int  value)  throws  IOException;
6  void  writeInt( int  value)  throws  IOException;
7  ...
8  }

 

 

 DataOutputStream  Class通过关键字implements实现了DataOutput 接口

  1 1 public class DataOutputStream extends FilterOutputStream implements DataOutput {

 2 
 3  2   public   final   void  writeBoolean ( boolean  value)  throws  IOException {
 4 
 5  3  write (value  ?   1  :  0 );
 6 
 7  4  }
 8 
 9  5  ...
10 
11  6  }

 

在接口定义的每一个方法都必须在实现类中实现。如果某一个方法没有被实现,编译的时候会出现一些错误:

DataOutputStream  should be declared abstract; it does not define writeBoolean(boolean) in DataOutputStream  .

 

  2. PHP:

interface MyInterface {

public function interfaceMethod($argumentOne, $argumentTwo);

}

class MyClass implements MyInterface {

public function interfaceMethod($argumentOne, $argumentTwo) {

return $argumentOne . $arguemntTwo;

}

}

class BadClass implements MyInterface {

// No method declarations.

}

// BadClass causes this error at run-time:

// Fatal error: Class BadClass contains 1 abstract methods and must therefore be

// declared abstract (MyInterface::interfaceMethod)

 

 3 C#:

 

interface MyInterface {

string interfaceMethod(string argumentOne, string argumentTwo);

}

class MyClass : MyInterface {

public string interfaceMethod(string argumentOne, string argumentTwo) {

return argumentOne + argumentTwo;

}

}

class BadClass : MyInterface {

// No method declarations.

}

// BadClass causes this error at compile-time:

// BadClass does not implement interface member MyInterface.interfaceMethod()

 

从上面不同的面向对象语言中可以看出,它们定义/处理接口的方式都差不多:

   1.接口定义了需要实现什么方法,这些方法需要什么参数;2.而实现类则显式声明接口中定义的方法并实现之。3.如果实现类没有把接口中所有的方法声明并实现之,则报错。

   当然,在JavaScript的面向对象编程中不能像上面的编程语言来定义,使用接口,因为javaScript中没有interface,implements等关键字,也没有编译的错误检查。

在JavaScript中模拟接口

   我们可以用以下三种方式来在JavaScript模拟接口:

     1.注释法 2.属性检测法 3 特征法

用注释的方法实现接口

/*

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) {

...

};

CompositeForm.prototype.getChild = function(index) {

...

};

// Implement the FormItem interface.

CompositeForm.prototype.save = function() {

...

};

  通过上面例子看到,我们用面向对象的方式定义了接口,并把它放置到注释中。这样,既不产生错误,又起了接口定义的作用。不过,这种方法还不能很好地模拟出接口,因为它没有检测机制--它不能保证,也不知道CompositeForm是否实现了Composite 接口中的所有方法。不过这种方法的好处也很明显--简单,而且不需要额外的帮助类或者方法来支持。

   

用属性检测来实现接口

 

/*

interface Composite {

function add(child);

function remove(child);

function getChild(index);

}

interface FormItem {

function save();

}

*/

var CompositeForm = function(id, method, action) {

//声明必须实现 'Composite','FormItem'接口
 this.implementsInterfaces = ['Composite', 'FormItem'];

...

};

...

function addForm(formInstance) {
if(!implements(formInstance, 'Composite', 'FormItem')) {

throw new Error("Object does not implement a required interface.");

}

...

}

// The implements function, which checks to see if an object declares that it
//接口检测

// implements the required interfaces.

function implements(object) {

for(var i = 1; i < arguments.length; i++) { // Looping through all arguments

// after the first one.

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) {

return false; // An interface was not found.

}

}

return true; // All interfaces were found.

}

从上面的例子看到,CompositeForm 中声明了该类必须要实现composite,formitem接口,检测没有实现,则抛出Error。

这种实现方式的优点如下:

1.记录了该类实现了哪几个接口。

2.如果该类没有实现它声明的接口,则会报错,这样,我们就可以强制性地让其他程序员必须实现这些接口。

但是,这种实现方式的缺点也很明显:

我们保证了实现类必须声明接口,但不能保证实现类一定实现了接口的所有方法。

 

3.特征法

  什么是特征法呢?打个比方,如果我们看见一种动物它走起来像鸭子,叫声像鸭子,生活习性也像鸭子,那么我们就认定它就是鸭子。用编程的角度来讲就是:如果一个类它声明了接口,而且实现了接口的所有方法,我们就认定了它实现了这些接口。容易理解吧~看例子:

// Interfaces.

var Composite = new Interface('Composite', ['add', 'remove', 'getChild']);

var FormItem = new Interface('FormItem', ['save']);

// CompositeForm class

var CompositeForm = function(id, method, action) { 
//implements Composite, FormItem’s method

...

};

...

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 class**/

 1  //  Constructor.
 2  var  Interface  =   function (name, methods) {
 3  if (arguments.length  !=   2 ) {
 4  throw   new  Error( " Interface constructor called with  "   +  arguments.length  +
 5  " arguments, but expected exactly 2. " );
 6  }
 7  this .name  =  name;
 8  this .methods  =  [];
 9  for ( var  i  =   0 , len  =  methods.length; i  <  len; i ++ ) {
10  if ( typeof  methods[i]  !==   ' string ' ) {
11  throw   new  Error( " Interface constructor expects method names to be  "
12  +   " passed in as a string. " );
13  }
14  this .methods.push(methods[i]);
15  }
16  };

 

// Static class method.

Interface.ensureImplements = function(object) {

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];

if(interface.constructor !== Interface) {

throw new Error("Function Interface.ensureImplements expects 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];

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.");

}

}

}

};

上面的例子中,帮助类Interface约束了实现类必须声明接口,实现接口的方法。 如果读者打算用设计模式来开发复杂的系统,我想这种方式会带来很大的好处。因为,对于大型的系统而言,会有很多程序员会一起参与开发,怎样让程序员更容易交流?代码质量更高?效率更高呢?当然就是规范了,接口就定义了一系列规范,其作用不言而喻。

下面再提供一个使用接口的范例:

  使用接口前的代码:

// 该类持有一个TestResult Object,并有了一个renderResults方法把测试结果输出到页面

var ResultFormatter = function(resultsObject) {

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);

}

return resultsContainer;

};

使用了接口类之后的代码

// 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() {

...

};
从上例中应该可以看出,重构后的代码可读性提高了?更重要的是,很多设计模式也依赖于接口,如:工厂模式,命令模式,油漆工模式等…接口只是我们为JavaScript设计模式铺平了道路…Amazing will coming soon..Contact with me:[email protected]

你可能感兴趣的:(JavaScript)