2014-10-04 48 views
1

这是Ruby书中实用面向对象设计的一个例子。我有兴趣将这个ruby代码翻译成JavaScript,以便更好地理解JS中的duck-typing。任何人都可以帮助翻译这段代码来澄清如何最好的写在Javascript中,或者至少帮助我开始?鸭子打字:使用鸭子打字将Ruby代码翻译成Javascript

此处的旅行类充当其他类(Mechanic,Trip_Coordinator,Driver)的接口。 Trip类中的准备方法使用Duck类型准备工具。

class Trip 
    attr_reader :bicycles, :customers, :vehicle 

    def prepare(preparers) 
     preparers.each {|preparer| 
     preparer.prepare_trip(self)} 
    end 
end 

class Mechanic 
    def prepare_trip(trip) 
    # Does something with trip.bicycles 
    end 
end 


class Trip_Coordinator 
    def prepare_trip(trip) 
    # Does something with trip.customers 
    end 
end 

class Driver 
    def prepare_trip(trip) 
    # Does something with trip.vehicle 
    end 
end 

更新:

我加入的代码,我认为这是上面的Ruby代码的可能翻译。然而,当我运行代码我得到以下输出和错误:

mountain 
2 
jeep 

/home/ubuntu/user/tests/trip.js:3 
     preparer.prepare_trip(this) 

TypeError: Object [object Object] has no method 'prepare_trip' 

意见或建议,将不胜感激,以进一步提高JS鸭打字的理解。

JavaScript代码:

var Trip = function(preparers){ 
    return preparers.forEach(function(preparer){ 
     preparer.prepare_trip(this) 
    } 
)}; 

var Mechanic = function(trip){ 
    // does something with trip.bicycles                                       
    prepare_trip: console.log(trip.bicycles); 
}; 

var TripCoordinator = function(trip){ 
    //does something with trip.customers                                       
    prepare_trip: console.log(trip.customers); 
}; 

var Driver = function(trip){ 
    //does something with trip.vehicle                                        
    prepare_trip: console.log(trip.vehicle); 
}; 

// customer wants to go on a trip for two and needs a car                                   
var planA = { 
    bicycles: "mountain", 
    customers: 2, 
    vehicle: "jeep" 
}; 

//customer wants to go a trip for one and only ride a bike                                   
var planB = { 
    bicycles: "road", 
    customers: 1 
}; 

Trip([new Mechanic(planA), new TripCoordinator(planA), new Driver(planA)]); 
Trip([new Mechanic(planB), new TripCoordinator(planB)]); 

更新2

每从下面FGB的解决方案和建议,我有地方我下面的问题,最终的解决方案。我添加了一个代理来删除调用者的依赖关系,他们必须知道在创建旅行计划时他们需要什么准备。

var Agent = function(plan){ 
    if("bicycles" && "customers" && "vehicle" in plan){ 
     Trip([new Mechanic(plan), new TripCoordinator(plan), new Driver(plan)]); 
    } 
    else if(!("vehicle" in plan) && "bicycles" && "customers" in plan){ //A driver is not needed                                   
     Trip([new Mechanic(plan), new TripCoordinator(plan)]); 
    } 
}; 

var Trip = function(preparers){ 
    return preparers.forEach(function(preparer){ 
     preparer.prepare_trip(this) 
    } 
)}; 
var Mechanic = function(trip){ 
    // does something with trip.bicycles                                       
    this.prepare_trip = function() { 
     console.log(trip.bicycles); 
    } 
}; 

var TripCoordinator = function(trip){ 
    //does something with trip.customers                                       
    this.prepare_trip = function() { 
     console.log(trip.customers); 
    } 
}; 

var Driver = function(trip){ 
    //does something with trip.vehicle                                        
    this.prepare_trip = function() { 
     console.log(trip.vehicle); 
    } 
}; 

// customer wants to go on a trip for two and needs a car                                   
var planA = { 
    bicycles: "mountain", 
    customers: 2, 
    vehicle: "jeep" 
}; 

//customer wants to go a trip for one and only ride a bike                                   
var planB = { 
    bicycles: "road", 
    customers: 1 
}; 

Agent(planB); 

相关SO讨论Example of Javascript Duck Typing?

+0

您可以使用Opal编译器自动将其翻译为JavaScript:http://www.sitepoint.com/opal-ruby-browser-basics/ – 2014-10-04 01:42:14

+0

@AndersonGreen:代码生成器如何帮助他们理解鸭子打字在JavaScript中? – 2014-10-04 02:26:34

+0

@ muistooshort如果这是一个学习练习,那么最好手动翻译它,当然。 – 2014-10-04 02:30:06

回答

1

的代码几乎是正确的,但你混淆了构造函数和对象文字语法。当你这样做:

var Driver = function(trip){ 
    //does something with trip.vehicle                                        
    prepare_trip: console.log(trip.vehicle); 
}; 

的“prepare_trip:”实际上是一个label,而没有定义对象的属性。

固定这将是一个方法:

var Driver = function(trip){ 
    //does something with trip.vehicle                                        
    this.prepare_trip = function() { 
     console.log(trip.vehicle); 
    }; 
}; 

还要注意的代码是不太一样的Ruby代码:

preparer.prepare_trip(this); 

这里,this是全局对象,而不是跳闸对象,并且该方法中不使用该参数。在你的代码中,trip参数是在preparer的construstor中传递的。

+0

您认为我提供的答案是最有效的解决方案吗?每次我打电话给旅行时,程序员都必须知道哪些编写者需要致电。你认为最好是进一步重构这些代码,以便只将计划传递给Trip,Trip函数根据具体计划决定哪些编写者需要被调用?再次感谢您的帮助。 – JnL 2014-10-04 11:30:36

+0

我会考虑这一点。这取决于你想要什么样的设计。如果trip函数可以决定哪些编写者不需要指定它们,那么这可能会使调用代码更简单。 – fgb 2014-10-04 11:54:36