Rails 如何才能很好地继承类,但又避免重复编码?

kevinhua · 2012年03月26日 · 最后由 poshboytl 回复于 2012年03月27日 · 3480 次阅读

以 Ruby China 的源代码为例,可以

继承 Model

class Movie < Topic
  ... ...
end

继承 Controller

class MoviesController < TopicsController
  ... ...
end

问题是: (1) MoviesController 中有必要复写 TopicsController 的方法吗?如果不复写,因为 Topics 中使用的是 Topic 类和@topic实例,如何才能自动使用 Movie 类和@movie实例。 (2) Views 又如何实现较为 DRY 的继承?

你这根本不是 Rails 的目的。而是 Ruby 的问题。貌似放错分类了吧?

(1) 当然没必要重写。 这个问题证明你还是对多态性还不甚了解。本身这个问题就不好回答,也不是一个好问题。 覆写不覆写,要看你要做什么。你可以覆写,也可以通过 super 调用,还可以通过设定不同的可见性来方便的调用超类的实例。但是总的来说,如果仅仅为了分享代码,在 Ruby 下面。首选混入同一个模块。

(2) Views 干嘛实现继承?

views 若真的不想复写,可以通过 render 的方式来避免. 按你的例子,如果你想复用 topics 的 show 页面,可以在 movies/show.html.erb 中直接 render :file => 'topics/show'.

controller 继承只在两种情况下用过,一个是为了 layout,另外一个是偷懒少写相同的 create 什么的,也就是 inherited_resources 这个 gem 干的事情。

inherited_resources 已经在 README 里已经放出了deprecation notice了,直接推荐使用 responders.

**Deprecation notice**
Since Rails 3 came out, I have no longer used Inherited Resources. I have found that the responders abstraction and custom Rails generators offer the perfect balance between hiding and showing too much logic. That said, I suggest developers to make use of the responders gem (at github.com/plataformatec/responders) and no longer use Inherited Resources.


如果没有什么特殊原因的话,最好少用继承。 继承虽好,但不能滥用。

如果你要定义一个新的 model movie 的话, 首先我建议你先不要用继承,model 层和 controller 层都先不要继承。

先从没有继承的结构开始编码, 编码完成后,如果发现重复度很高的话, 可以考虑提取共用的函数。

其次,给你个建议, controller 的 action 最好不要定义在基类中, 否则代码会很混乱,这种混乱带来的危害, 远远高于,因为继承,代码量减少,所带来的好处, 正所谓得不偿失

避免重复编码 这个原则 要有一个尺度,不能太过分。

真爱生命,远离 OO,拥抱 FP

如果只看 Movie < Topic,那么我的理解就是多表继承,如果是多表继承,那么只需要写 topic 的 controller 和 view,路由里多写几条 resources,controller 和 view 中使用 [xx,xx] 的方式来写路由就 ok

#1 楼 @kevinhua 不用刻意要求自己,多写,熟能生巧。写多了你就会想怎么减少代码量,避免重复代码,重复逻辑,提高复用程度。 别人的代码风格也不用太深究,一时发挥而已,一个 forum,我相信你自己梳理一下思路,也能够实现个大概,此时再去看看别人的写得好点的代码,再学习是很有用的。

楼主你 model 是在做单表继承吗?这没任何问题,虽然看起来 Movie 和 Topic 不太像一个继承关系。 我之所以会这么问是因为,我认为共享方法只是一个结果,而不是单纯为了共享方法而去继承一下。共享方法的方式有很多,而用继承那么应该是因为他们有着一种“继承”的关系。听起来好绕 :D

关于 controller 部分,我觉得这里没必要做继承。原因就是 MoviesController 和 TopicsControllerm 没有继承关系。有的是他们的 model,而不是他们的 controller。

补充一点就是,action 本身并不应该在多个 controller 里共享。如果一定有需求,就写一个类似 BaseController 的东西,让其它 controller 继承它。

如果 controller 里有非 action 的方法需要共享可以考虑是否能放在 application controller。

忘记回答你第二个问题了。view 的重用就用 partial 吧...

需要 登录 后方可回复, 如果你还没有账号请 注册新账号