[JavaScript] JavaScript 面向对象设计 (3) : 多态与界面篇

在前一篇中我们介绍了基础的 JavaScript 继承实践法,透过 Object.prototype 我们可以自由决定对象要继承自哪个对象,也可以扩充对象目前现有的属性和方法 (和 C# 的 Extension Method 有异曲同工之妙),在本篇中,我们要来介绍面向对象的另一个特性:多态 (Polymorphism)。


在前一篇中我们介绍了基础的 JavaScript 继承实践法,透过 Object.prototype 我们可以自由决定对象要继承自哪个对象,也可以扩充对象目前现有的属性和方法 (和 C# 的 Extension Method 有异曲同工之妙),在本篇中,我们要来介绍面向对象的另一个特性:多态 (Polymorphism)

多态的定义是,相同的行为 (behavior),在不同的对象上会有不同的反应。最常被举的例子就是动物或车子了,例如我有一个 Car 对象,里面有一个 getName() 方法,而我们定义了 HondaCRV 和 ToyotaWish 两个对象来继承它,其完整定义为:

   1:  function Car() {
   2:   
   3:      this.name = "BASE";
   4:   
   5:      this.getName = function () { return this.name; };
   6:      this.drive = function () { document.write("Drive BASE 
"); };
   7:   
   8:  }
   9:   
  10:  function HondaCRV() {
  11:      HondaCRV.prototype.name = "HONDA CRV";
  12:  }
  13:   
  14:  HondaCRV.prototype = new Car();
  15:   
  16:  function ToyotaWish() {
  17:      ToyotaWish.prototype.name = "TOYOTA Wish";
  18:  }
  19:   
  20:  ToyotaWish.prototype = new Car();

然后在主程序这样调用:

   1:  function init() {
   2:   
   3:      document.write((new Car()).getName() + "
");
   4:      document.write((new HondaCRV()).getName() + "
");
   5:      document.write((new ToyotaWish()).getName() + "
");
   6:   
   7:  }

可得到这样的结果:

image

这个范例程序就是典型的多态运用,虽然它共用了父类的变量,不过我们还可以再进一步做多态的能力。在 Car 中有一个方法 drive(),现在我们要在 HondaCRV 和 ToyotaWish 中覆写它,程序如下:

   1:  function Car() {
   2:   
   3:      this.name = "BASE";
   4:   
   5:      this.getName = function () { return this.name; };
   6:      this.drive = function () { document.write("Drive BASE 
"); };
   7:   
   8:  }
   9:   
  10:  function HondaCRV() {
  11:      HondaCRV.prototype.name = "HONDA CRV";
  12:      HondaCRV.prototype.drive = function () {
  13:          document.write("Drive HONDA CRV now. 
");
  14:      };
  15:  }
  16:   
  17:  HondaCRV.prototype = new Car();
  18:   
  19:  function ToyotaWish() {
  20:      ToyotaWish.prototype.name = "TOYOTA Wish";
  21:      ToyotaWish.prototype.drive = function () {
  22:          document.write("Drive TOYOTA Wish now. 
");
  23:      };
  24:  }
  25:   
  26:  ToyotaWish.prototype = new Car();

请注意,我们现在使用了 Object.prototype.[method] 的方式来覆写父对象的方法,以执行对象自己的动作。然后修改主程序:

   1:  function init() {
   2:   
   3:      document.write((new Car()).getName() + "
");
   4:      document.write((new HondaCRV()).getName() + "
");
   5:      document.write((new ToyotaWish()).getName() + "
");
   6:   
   7:      (new Car()).drive();
   8:      (new HondaCRV()).drive();
   9:      (new ToyotaWish()).drive();
  10:   
  11:  }

执行它,我们可以得到下面的结果:

image

到了这里,我想你应该了解如何使用 JavaScript 实践多态的功能了,接着我们就要来做和多态有高度相关的功能:界面 (interface)

有写过 C#/Java/VB 这种面向对象语言程序的人应该都知道,界面是一种合约 (contract),它具有很强的强制性,只要是有参考界面但未实践的话会被掷回编译错误,所以不用担心界面没有被实践,然而 JavaScript 是一种类型松散的直译式语言,没办法强制执行这种检查,所以这部分我们得自己做,不过 JavaScript 有些方便的辅助对象,可以帮我们解决一些事情。

例如,我们订了一个 IRateCalculator 界面,里面有一个 getAmount() 方法:

   1:  function IRateCalculator() {
   2:      // contract method.
   3:      this.getAmount = function (amount) { throw "ERROR_INTERFACE_METHOD_MUST_BE_IMPLEMENTED"; };
   4:  }

然后我们定义了两个对象 SavingCalculator 与 LoanCalculator,皆实践 IRateCalculator 界面,定义自己的 getAmount() 方法:

   1:  SavingCalculator.prototype = new IRateCalculator();
   2:   
   3:  function SavingCalculator(amount) {
   4:   
   5:      this.amount = amount;
   6:   
   7:      SavingCalculator.prototype.getAmount = function (amount) {
   8:          return amount * 1.01; // 1%
   9:      };
  10:   
  11:  }
  12:   
  13:  LoanCalculator.prototype = new IRateCalculator();
  14:   
  15:  function LoanCalculator(amount) {
  16:   
  17:      this.amount = amount;
  18:   
  19:      LoanCalculator.prototype.getAmount = function (amount) {
  20:          return amount * 1.20; // 20%
  21:      };
  22:   
  23:  }

在主程序中我们要使用 SavingCalculator 和 LoanCalculator 计算十万元的本利和:

   1:  function init() {
   2:   
   3:      var saving = new SavingCalculator();
   4:      var loan = new LoanCalculator();
   5:   
   6:      // check interface.
   7:      console.log(IRateCalculator.prototype);
   8:      console.log(SavingCalculator.prototype);
   9:      console.log(typeof SavingCalculator.prototype.getAmount);
  10:   
  11:      if (IRateCalculator.prototype.isPrototypeOf(saving))
  12:          document.write("Saving's Rate Amount of 100000 is: " + saving.getAmount(100000) + "
");
  13:      else
  14:          document.write("Your code is not implement IRateCalculator interface.");
  15:   
  16:      if (IRateCalculator.prototype.isPrototypeOf(loan))
  17:          document.write("Loan's Rate Amount of 100000 is: " + loan.getAmount(100000) + "
");
  18:      else
  19:          document.write("Your code is not implement IRateCalculator interface.");
  20:   
  21:  }

执行结果为:

image

看起来很平常吧,但其实问题有两个:

1. 主程序必须要确认对象有实践 IRateCalculator 界面。
2. 主程序必须检查对象确实实践了 IRateCalculator.getAmount() 方法。

针对第一个问题,我们可以利用 Object.prototype.isPrototypeOf() 方法来确认,它可以检查界面是否被某对象实践,因此我们检查了这件事,并决定是否要调用 getAmount() 方法。然而第二个问题仍无解,因为 Object.prototype 无法回传更多的类型资讯,因此无法得到确实的类型比对依据,无法很确定 SavingCalculator 和 LoanCalculator 的 getAmount() 确实就是 IRateCalculator.getAmount() 方法,只能够暂时信任对象实践的确实是界面所定义的方法。

善用多态,可以创造出很多不同的 JavaScript 对象应用,而且它也能做为 Design Pattern 的入口基石,让编写可高度重复使用的 JavaScript 程序能更加容易。

原文:大专栏  [JavaScript] JavaScript 面向对象设计 (3) : 多态与界面篇


猜你喜欢

转载自www.cnblogs.com/chinatrump/p/11496454.html