我有一个JavaScript MVC设计,使用原型实现,其中不同的项目可能以控制器决定的不同方式显示。例如,可以与观看ViewTabs
或ViewSimple
一起显示“事件”项目。类层次结构:
ViewBase
- ViewTabs
-- EventViewTabs, which implements EventViewTabs.Validate
- ViewSimple
-- EventViewSimple, which implements EventViewSimple.Validate
决定是否使用EventViewTabs
或EventViewSimple
是由EventController
完成的。我的问题是:我有Validate
方法来检查来自Event
视图的输入,但此方法对于EventViewTabs
和EventViewSimple
视图是相同的。我应该在哪里放Validate
以避免重复?我无法将其放在ViewBase
中,因为其他项目(例如User
)也会继承此类。
似乎我需要多重继承,但是有更聪明的方法吗?我有一种感觉,我忽视了一些显而易见的事情。
答案 0 :(得分:3)
您缺少作品。继承不是代码重用的所有问题的答案,以避免复制 - 粘贴编程。
让我们说你是View
基础原型:
function View() { }
如果您希望此视图支持验证,您可以在构造函数中注入验证依赖:
function View(validator) {
this.validator = validator;
}
View.prototype = {}; // A lot of functions here
也就是说,现在任何继承View
原型的视图都会有一个相关的验证器。换句话说:您不需要在具体视图中派生出两个原型(您不需要而且无论如何都不能这样做。)
另一方面,就面向对象编程而言,从Validator
派生以创建View
是没有意义的。
当你说一个视图有一个验证器时,由于你正在使用将作为动词,你就是在谈论一个关联(一种形式的组合物)。或者,当您说我的主屏幕 为视图时,我们正在谈论继承,因为特定视图必须也是一个视图,因此它需要基本视图的成员像一个视图。
答案 1 :(得分:1)
基本上,您的验证器可以根据其必须使用的类型进行定制。在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
实例是什么,它们都会实现自己的特定验证器,可以通用方式调用。
答案 2 :(得分:0)
一种方法是使用mixins来添加其他行为(这是ruby方法,并且也被react.js和react.rb使用)你可以谷歌搜索javascript + mixins并找到一些像这样的优秀教程: http://raganwald.com/2014/04/10/mixins-forwarding-delegation.html
对于您的具体案例,validate
(或者validator
)将是混合。
答案 3 :(得分:0)
为什么不这样做: ViewBase
ViewBase
-EventValidator, which implements Validate
--ViewTabs
---EventViewTabs
--ViewSimple
---EventViewSimple.
同时考虑使用合成而不是继承,请参阅this video