【问题标题】:Multiple inheritance in Javascript with prototype chainJavascript中的多重继承与原型链
【发布时间】:2016-04-03 10:01:49
【问题描述】:

我有一个 JavaScript MVC 设计,使用原型实现,其中不同的项目可以由控制器决定以不同的方式显示。例如,“事件”项可以与视图ViewTabsViewSimple 一起显示。类层次结构:

ViewBase
- ViewTabs 
-- EventViewTabs, which implements EventViewTabs.Validate
- ViewSimple
-- EventViewSimple, which implements EventViewSimple.Validate

决定是使用EventViewTabs 还是EventViewSimpleEventController 完成。我的问题是:我有一个Validate 方法来检查来自Event 视图的输入,但是这个方法对于EventViewTabsEventViewSimple 视图是相同的。为了避免重复,我应该把Validate放在哪里?我不能把它放在ViewBase,因为其他项目(例如User)也继承自这个类。

似乎我需要多重继承,但有更聪明的方法吗?我有一种感觉,我忽略了一些明显的东西。

【问题讨论】:

    标签: javascript model-view-controller multiple-inheritance prototypal-inheritance


    【解决方案1】:

    你缺少作曲。继承并不是所有代码重用问题的答案,以避免复制粘贴编程

    假设你有一个View基础原型

    function View() { }
    

    如果你想让这个视图支持验证,你可以在构造函数中注入验证依赖

    function View(validator) {
       this.validator = validator;
    }
    View.prototype = {}; // A lot of functions here
    

    也就是说,现在任何继承View 原型的视图都会有一个关联的验证器。换句话说:您不需要在具体视图中派生两个原型(您不需要也不能这样做)。

    另一方面,就面向对象编程而言,从Validator 派生来创建View 是没有意义的。

    当你说 一个视图有一个验证器,因为你使用 has 作为动词,你在谈论一个关联(composition 的一种形式)。或者,当您说我的主屏幕作为视图时,我们说的是继承因为特定的视图必须是也是一个视图,所以它需要基础视图的成员像视图一样工作

    【讨论】:

      【解决方案2】:

      基本上,您的验证器可以根据需要使用的类型进行定制。在 UML 中,它被称为组合。我弄清楚你的代码如下:

      function Validator {}
      Validator.prototype.validate = function(arg) {
        //arg is no longer inputs
        return true|false; //the ultimate output along with additional information;
      }
      
      function EventViewTabsValidator() {}
      EventViewTabsValidator.prototype = Object.extend(Validator.prototype); //inheritance
      EventViewTabsValidator.prototype.constructor = EventViewTabsValidator; //enforce the constructor to point to your derived type
      EventViewTabsValidator.prototype.validate = function() {
        var inputs = $('inputs');
        var param = 'do some stuff specific to EventViewTabsValidator based on the inputs';
        return Validator.prototype.validate.call(this, param); //pass param, not inputs
      }
      
      function EventViewSimpleValidator() {} 
      EventViewSimpleValidator.prototype = Object.extend(Validator.prototype); //inheritance
      EventViewSimpleValidator.prototype.constructor = EventViewSimpleValdiator; //enforce the constructor to point to your derived type
      EventViewSimpleValidator.prototype.validate = function() {
        var inputs = $('inputs');
        var param = 'do some stuff specific to EventViewSimpleValidator based on the inputs';
        return Validator.prototype.validate.call(this, param); //pass param, not inputs
      }
      
      
      function EventViewTabs() {
        this.validator = null; //see init
      }
      EventViewTabs.prototype.init = function() {
        this.validator = new EventViewTabsValidator();
      }
      function EventViewSimple() {
        this.validator = null; //see init
      }
      EventViewSimple = function() {
        this.validator = new EventViewSimpleValidator();
      }
      

      您可以将这两种类型抽象为基础EventView,这可能会暴露this.validator。 您的EventController 实例将调用:

      var simple = new EventViewSimple();
      simple.validator.validate();
      
      var tabs = new EventViewTabs();
      tabs.validator.validate();
      

      无论EventView 实例是什么,它们都实现了自己的特定验证器,可以以通用方式调用。

      【讨论】:

      • 谢谢,看来这是我自己想不出的明显解决方案!
      【解决方案3】:

      一种方法是使用 mixins 来添加其他行为(这是 ruby​​ 方法,react.js 和 react.rb 也使用)你可以在 google 上搜索 javascript+mixins 并找到一些像这样的优秀教程: http://raganwald.com/2014/04/10/mixins-forwarding-delegation.html

      对于您的具体情况,validate(或者可能是 validator)将是 mixin。

      【讨论】:

        【解决方案4】:

        为什么不这样做: 视图库

        ViewBase
        -EventValidator, which implements  Validate
        --ViewTabs
        ---EventViewTabs
        --ViewSimple
        ---EventViewSimple.
        

        还可以考虑使用组合而不是继承,请参阅this video

        【讨论】:

        • 我可能应该更具体一点:其他类也继承自 ViewTabs 和 ViewSimple,因此这些类不能继承自 EventValidator。不过,感谢您提供有关构图的提示。
        猜你喜欢
        • 2015-10-14
        • 1970-01-01
        • 2013-11-07
        • 2017-09-02
        • 2015-11-13
        • 2013-05-09
        • 2019-01-24
        相关资源
        最近更新 更多