我正在我的应用程序中集成的一些开源代码包含一些包含该效果代码的类:
class SomeClass < SomeParentClass def self.new(options = {}) super().tap { |o| # do something with `o` according to `options` } end def initialize(options = {}) # initialize some data according to `options` end end
据我所知,self.new和initialize都做同样的事情 – 后者“在施工期间”和前者“施工后”,它看起来像一个可怕的模式使用 – 为什么分裂对象初始化为两部分,其中一部分显然是“错误思考(tm)”?
解决方法
理想情况下,我想看看super()里面有什么.点击{| o |阻止,因为虽然这看起来像是不好的做法,但也许在调用initialize之前或之后需要进行一些交互.
如果没有上下文,你可能只是在看一些有效的东西,但在Ruby中并不算是好习惯.
但是,单独的self.new和initialize方法的方法可能允许框架设计器实现框架的子类可用部分,并且仍然确保框架所需的设置完成,而不需要特别使用super()的稍微笨拙的文档.如果最终用户仅通过子类MyClass<获得他们期望的功能,那么文档和更干净的API会稍微容易一些. FrameworkClass并没有一些额外的注意事项:
When you implement the subclass
initialize
,remember to putsuper
at the start,otherwise the magic won’t work
. . .我个人认为这个设计有问题,但我认为至少会有明确的动机.
可能有更深层次的Ruby语言使代码在自定义self.new块中运行 – 例如,它可能允许构造函数在返回之前切换或更改特定对象(甚至返回不同类的对象).但是,我很少看到这样的事情在实践中完成,几乎总有一些其他方法来实现这些代码的目标而无需定制新的.
> Struct.new,可以选择获取类名并返回该动态创建的类的对象.
> In-table inheritance for ActiveRecord,允许最终用户从表中加载未知类的对象并接收正确的对象.
后者可以通过不同的ORM设计来避免继承(尽管所有这些方案都有优点/缺点).