Duck类型化:利用Duck类型化将Ruby代码翻译成Javascript

Duck类型化:利用Duck类型化将Ruby代码翻译成Javascript,javascript,ruby,oop,duck-typing,Javascript,Ruby,Oop,Duck Typing,这是Ruby book中实用的面向对象设计的一个例子。我有兴趣将这个ruby代码翻译成javascript,以便更好地理解JS中的duck类型。有人能帮我翻译这段代码,以澄清如何最好地用Javascript编写这段代码,或者至少能帮我入门吗 这里的trip类充当其他类(机械师、trip_协调员、驾驶员)的接口。其中,类Trip中的prepare方法使用Duck类型preparer class Trip attr_reader :bicycles, :customers, :vehicle

这是Ruby book中实用的面向对象设计的一个例子。我有兴趣将这个ruby代码翻译成javascript,以便更好地理解JS中的duck类型。有人能帮我翻译这段代码,以澄清如何最好地用Javascript编写这段代码,或者至少能帮我入门吗

这里的trip类充当其他类(机械师、trip_协调员、驾驶员)的接口。其中,类Trip中的prepare方法使用Duck类型preparer

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中duck类型的理解,我们将不胜感激

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

相关讨论

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

var Driver = function(trip){
    //does something with trip.vehicle                                                                                                                                                             
    prepare_trip: console.log(trip.vehicle);
};
“prepare_trip:”实际上是一个属性,并不定义对象的属性

一种解决方法是:

var Driver = function(trip){
    //does something with trip.vehicle                                                                                                                                                             
    this.prepare_trip = function() {
        console.log(trip.vehicle);
    };
};
还要注意的是,代码与Ruby代码并不完全相同:

preparer.prepare_trip(this);

这里,
这个
是全局对象,而不是trip对象,并且该参数不在方法中使用。在您的代码中,trip参数将被传递给编写者的构造函数。

您可以使用Opal编译器将其自动转换为JavaScript:@AndersonGreen:代码生成器如何帮助他们理解JavaScript中的duck类型?@muistooshort如果这是一个学习练习,当然,最好是手工翻译。这里似乎缺少很多东西。您想知道的DT是否只存在一个
prepare\u trip
方法?你有没有试过用JavaScript写这篇文章,但遇到了什么具体的问题?我更新了Mechanical方法来添加缺少的结尾。手动翻译比使用自动翻译更有帮助。我还没有将这段代码翻译成JS。我想知道的鸭子类型是,如果需要的话,能够在以后添加一个perparer。这就是本文中这个ruby示例的主要原因。通过更大的抽象,使您的代码能够适应未来的更改。在我在JS中学习了这项技术之后,我想把它应用到我自己对JS编程的兴趣上。你认为我提供的答案是最有效的解决方案吗?每次我给trip打电话时,程序员都必须知道需要打电话给哪些准备人员。您是否认为进一步重构此代码会更好,以便只将计划传递给Trip,Trip函数根据特定的计划决定需要调用哪些编制者?再次感谢你的帮助,我会考虑的。这取决于你想要什么样的设计。如果trip函数可以决定调用哪些准备程序,而不需要调用方指定它们,那么调用代码就更简单了。