我似乎经常遇到一些设计问题,我从来不知道什么才是真正合适的。一方面,我经常听到我应该限制耦合,坚持单一的责任,但当我这样做时,我经常发现很难在需要的时候将信息传递到程序的一部分。例如,
class Singer
def initialize(name)
@name = name
end
attr :name
end那么Song应该是:
class Song
def new(singer)
@singer = singer
end
end或
class Song
def new(singer_name)
@singer_name = singer_name
end
end后者的耦合性较小,因此根据原则我应该使用它。但是,如果我后来在Song中发现了一些需要更多了解歌手的东西,我的情况就不好了。例如:
class Song
...
def play
puts "Belting it out by #{@singer.name}, winner of
#{@singer.grammy_count} grammies!"
end
end如果我使用的是后面的Song类,而不是前者,那我就麻烦了。但我怀疑有人会提醒我SRP,单一责任原则,并建议:
class SongPlayer
def initialize(singer, song)
@singer, @song = singer, song
end
def play
puts "Belting it out by #{@singer.name}, winner of
#{@singer.grammy_count} grammies!"
end
end是的,我想这是有道理的,因为另一个歌手可能会翻唱另一个人的歌,对吗?但是,这真的会是同一首歌吗?在我的大多数情况下,它从来都不是同一首“歌”,所以我从来没有那种情况。那么,SRP是否值得为代码添加额外的类呢?
我有时认为,许多OOP原则,无论可靠与否,都源于Java的局限性,并不能很好地应用于Ruby。
发布于 2011-11-24 18:17:38
耦合应该与另一个概念相抗衡。您希望在两者之间取得平衡,而不是将其中之一发挥到极致。在您的示例中,singer_name似乎属于Singer,因此为了保持内聚力,您应该将Singer对象传递给Song,而不是name。
更广泛地说,您需要记住这些原则仅仅是指导原则。你必须始终运用常识和你对问题领域的独特理解。很少有明确的情况-它甚至可能随着应用程序的增长或随着您更好地理解领域而发生变化。
发布于 2011-11-24 18:26:14
面向对象的程序应该对真实的对象进行建模。在生活中,一首歌属于一个歌手,而不是歌手的名字,在你的程序中,你应该以这种方式来模仿它。
正如@troelskn已经提到的,有耦合的概念,但也有内聚的概念……原则是伟大的,但常识应该优先。
发布于 2011-11-24 18:30:02
Ruby的核心是程序员has 。你应该考虑代码的可读性,以及它对你(或你的同事)大脑的压力,特别是当你必须在长时间停顿后再次阅读和理解它的时候。
我想说,SRP应该被视为一种建议,而不是规则。如果SongPlayer使理解发生了什么变得更加困难,那么就放弃SRP并坚持使用Song#play,如果它能让它变得更容易,那么一定要使用它。
记住,你总是可以重构的。我会从Song#play开始,如果Song开始因为与播放相关的代码而变得臃肿,那么我会将其重构为一个SongPlayer类。
https://stackoverflow.com/questions/8255360
复制相似问题