如何将一个对象从一个对象的数组移动到另一个具有最少依赖性的对象的数组?

How can I move an object from one object's array to another object's array with the fewest dependencies?

我有两个带有容器数组的对象(Station 和 Carriage),我想将第三个对象(Passenger)从车站移动到车厢。

我在我的车厢中使用了以下方法 class(乘客只是一个空数组),但是虽然这确实让乘客登上了车厢,但他们仍然留在车站,这意味着我只是克隆它们而不是移动它们。

def board(passenger)
  passengers << passenger
end

我可以通过将另一个参数传递给 board 方法(车站)来解决这个问题,然后从车站自己的数组中删除所有乘客,如下所示,但这似乎是不好的做法。

def board(passenger, station)
  passengers << passenger
  station.passengers.delete(passenger)
end

我一直在阅读有关面向对象设计的内容,并且意识到我应该尽量减少 classes 之间的任何依赖关系...并且上面的代码似乎违反了良好 OOD 的许多准则,因为:

  1. 我的马车 class 正在到达车站 class
  2. 我的棋盘方法取决于在 正确顺序

有没有更好的方法让我用更少的 class 依赖项来实现这个目标?

你不想在你的方法中添加第二个参数是对的 - 你不需要。

相反,创建一个 Passenger 实例方法来为您处理此问题:

passenger.remove_from_station

代码可以是:

def remove_from_station
  Station.delete(self)
end

这样您就不必在方法调用中添加一堆冗余的、脆弱的参数。

那么乘客登机时:

def board(passenger)
  passengers << passenger
  passenger.remove_from_station
end

编辑: 看看。在许多情况下,它很可能是更好的解决方案。

改一下你的问题:谁应该管理 Passenger 和 Carriage 之间的关系,以及 Passenger 和 Station 之间的关系?

我认为您已经正确地认识到,无论是让马车管理乘客与车站的关系,还是让车站管理乘客与车厢的关系,都是没有意义的。

最简单的解决方案似乎是让 Passenger 管理自己与 Carriage 和 Station 的关系。例如:

class Passenger
  attr_reader :station, :carriage

  def enter_carriage(new_carriage)
    leave_station!
    @carriage = new_carriage
    self.carriage.add_passenger(self)
  end

  def leave_carriage!
    self.carriage.remove_passenger(self)
    @carriage = nil
  end

  def enter_station(new_station)
    leave_carriage!
    @station = new_station
    self.station.add_passenger(self)
  end

  def leave_station!
    self.station.remove_passenger(self)
    @station = nil
  end
end

这样Carriage和Station只需要提供add_passengerremove_passenger,内部实现可以随意更改

P.S。看来您在建立 OOP 基础方面做得很好。如果您正在寻找一本以 Ruby 为中心的 OOP 书籍,我 高度 推荐 Sandi Metz 的 Practical Object-Oriented Design In Ruby.

如果你从消息的角度考虑,事情会变得更容易理解 out.At 首先乘客属于 Station。因此,当 Carriage 想让乘客上车时,它必须向 Station 发送消息,要求它送乘客上车。所以我认为实现这一点的更好方法是:

class Station
  # First version
  # get any passenger
  def get_passenger
     # this will return the first one and remove it from the array
     passengers.shift       
  end 

  # Second version
  # Get a specific passenger
  # in this case the board method of Carriage 
  # will normally depend on the passenger as 
  # well as the station
  def get_passenger(passenger)
     if(passengers.include?(passenger))
       passengers.delete(passenger)
     else
       raise "Passenger not found!"
     end
  end
end

Carriage class 的 board 方法中,您只需要依赖注入 station 乘客登机的地方。

class Carriage
  # board any passenger from the station
  def board(station)
    passengers << station.get_passenger
  end
  # Board a specific passenger from the station
  def board(passenger, station)
    passengers << station.get_passenger(passenger)
  end
end

如果您不想按此顺序注入参数,并且您使用的是 Ruby >= 2.1,则可以改用 Ruby keyword arguments

我想到的另一种方法是让消息在乘客和车站、乘客和车厢之间流动。

class Passenger
  # the passenger can be in one station or
  # one carriage at the same time
  attr_accessor :station, :carriage

  def board(carriage)
    carriage.board(self)
    station.remove_passenger(self)
  end
end

class Station
  attr_accessor :passengers
  def remove_passenger(passenger)
    passengers.delete(passenger)
  end
end

class Carriage
  attr_accessor :passengers
  def board(passenger)
    passengers << passenger
  end
end

现在您只需提供要登机的车厢即可制作乘客登机板。

passenger.board(carriage) 

这里有一些很好的答案,但也有支持和反对所有这些方法的论点。

解决问题的关键是确定三个对象的正确职责。

车厢和车站都负责容纳乘客,并提供增减乘客的接口。两者都不负责维护当前包含乘客的对象的状态。 (即车站不负责将下车的乘客从车厢中带走。)

乘客应负责维护其当前位置 - 但这不应与位置本身紧密相关。

因此,除了 enter stationenter_carriage 等,还可以简单地使用 enter 方法接收一个对象,该对象提供进入和离开的接口(例如马车或车站)。然后乘客只需离开当前容器并进入新容器。

p.s。不要使用 bang 方法(例如 leave_station!),除非您希望提醒其他开发人员使用此方法比使用其他提供的替代方法存在特定的危险。本例中的 bang 具有误导性,因为该方法是一个普通的增变器。