我有两个带有容器数组的对象(Station和Carriage),我想将第三个对象(Passenger)从一个工作站移动到一个支架。
我在我的Carriage课程中使用了以下方法(乘客只是一个空阵列),但是虽然这确实登上了车厢上的乘客,但他们仍然留在车站,这意味着我只是克隆他们而不是移动它们。
def board(passenger)
passengers << passenger
end
我可以通过将另一个参数传递给棋盘方法(火车站)然后从火车站自己的阵列中删除乘客来解决这个问题,如下所示:但这似乎是不好的做法。
def board(passenger, station)
passengers << passenger
station.passengers.delete(passenger)
end
我一直在阅读有关面向对象设计的内容,并且我意识到我应该尽可能减少类之间的任何依赖关系...而且上面这段代码似乎藐视了许多优秀OOD的指导原则,因为:
我是否有更好的方法来实现这一目标,减少类依赖性?
答案 0 :(得分:1)
你是不是想在你的方法中添加第二个参数 - 你不需要。
相反,请创建一个Passenger实例方法,为您解决此问题:
passenger.remove_from_station
代码可以是:
def remove_from_station
Station.delete(self)
end
这样您就不必在方法调用中添加一堆冗余,易碎的参数。
然后乘客登机时:
def board(passenger)
passengers << passenger
passenger.remove_from_station
end
答案 1 :(得分:1)
如果从消息的角度考虑,事情会更容易弄明白。首先,乘客属于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
班级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&gt; = 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)
答案 2 :(得分:0)
修改:查看Nafaa's solution。在许多情况下,这可能是一个更好的解决方案。
重新解释你的问题:谁应该管理乘客和车厢之间以及乘客和车站之间的关系?
我认为您已经正确地确定了,对于Carriage来说,管理乘客与车站的关系,以及车站管理乘客与车厢的关系都没有意义。
最简单的解决方案似乎是让乘客管理自己与马车和车站的关系。例如:
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 and Station只需提供add_passenger
和remove_passenger
,其内部实现可以自由更改。
P.S。看起来你在建立自己的OOP基础方面做得很好。如果您正在市场上寻找一本以Ruby为中心的优秀OOP书籍,我高度推荐Sandi Metz&#39; Practical Object-Oriented Design In Ruby
答案 3 :(得分:0)
这里有一些很好的答案,但有支持和反对所有这些方法的论据。
解决问题的关键是确定三个对象的正确职责。
车厢和车站均负责容纳乘客并为乘客提供添加和移除的接口。两者都不负责维持当前包含乘客的物体的状态。 (即,当乘客下车时,车站不负责将乘客从车厢中移走。)
乘客应负责维护其当前位置 - 但这不应与位置本身紧密耦合。
所以,不是让enter station
,enter_carriage
等,而是可以使用enter
方法接收一个提供进入和离开界面的对象(例如马车或车站) )。然后乘客只需离开当前容器并进入新容器。
P.S。不要使用爆炸方法(例如leave_station!
),除非您希望提醒其他开发人员使用此方法与某些其他提供的替代方案存在特定危险。在这种情况下的爆炸是误导,因为该方法是一个正常的变异器。