这是Ruby书中实用面向对象设计的一个例子。我有兴趣将这个ruby代码翻译成javascript,以便更好地理解JS中的duck-typing。任何人都可以帮助翻译此代码,以阐明如何最好地在Javascript中编写此代码或至少帮助我开始?
此处的旅程类充当其他类(Mechanic,Trip_Coordinator,Driver)的界面。 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中鸭子类型的理解。
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);
答案 0 :(得分: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对象,并且该方法中不使用该参数。在您的代码中,trip参数将在preparer的construstor中传递。