重构 模块与类的使用规范

sennmac · 2015年12月16日 · 最后由 lgn21st 回复于 2015年12月16日 · 3844 次阅读

首先看一段Ruby代码

#定义
module A
  def self.a
    puts 'a'
  end
end
#使用
A.a

上面可以看到定义了一个A模块,然后在被使用时是通过A模块来调用a这个类方法。 但是我认为模块的从根本上是为了解决代码复用问题而存在,模块封装了一组被公用的常量/方法/变量,供其他模块/类进行引入。 在上面的代码中出现了两个不规范的地方 1.模块中不应该定义类方法,因为模块中的类方法永远无法被include成为目标类的类方法,这违反了模块设计的初衷。 2.如果希望某个方法以类方法的形式被调用到,使用class进行封装。 请大家给出意见。谢谢。么么哒。 -------update------- 原贴内容有点误人子弟了。 我原本以为module从设计上是为了

  1. mixin :提供一组方法/变量/常量以便混入其他模块/类。 2.namespace:提供命名空间。 除此之外对module的用法都是不规范的。 但是实际上module也可以做为Utility使用。 在官方的Math模块中,便提供了Math.cos,Math.sqrt 等一系列的辅助方法。
共收到 14 条回复

请问从楼主的角度,能否给出不要把类方法定义在模块中的理由呢?

首先模块中允许定义类方法,且在很多场景下就应该这么干,例子到处都是(其实我觉得不应该叫类方法,而应该叫静态方法,或者 static method 感觉更合适,至少 ES6,Swift 都是这样叫的)

除了在模块中用 self.method_name 来定义之外,还有很多种办法达到同样的结果。

module A
  extend self
  def a
    puts 'a'
  end
end

还有

module A
  def a
    puts 'a'
  end
  module_function :a
end

#1楼 @lgn21st 并不是说“能不能”,而是“规范不规范”。 模块的类方法注定了无法被目标类inlucde到。 可能我代码看的少,您能给出一些您看到的在模块中定义类方法的场景吗。

module A1
  def a
    puts 'a'
  end
  module_function :a
end

class B;include A1;end
#报错
B.a

module A2
  extend self
  def a
    puts 'a'
  end
end
class B;include A2;end
#报错
B.a

#2楼 @sennmac module 中定义类方法是有用的,不是说无法被类 include 并当作类的类方法用,在 module 中定义类方法就不符合"规范"。

随便搜了一个例子,也许不能说明实际问题 https://gist.github.com/sshaw/53c27b148e903a07e494

#3楼 @lgn21st THX。 下班之后我看看这段代码。 有问题的话,我还会提出来的,多谢您指教。

#4楼 @sennmac 我随便搜了一个例子,是 module_function 的一个应用场景,刚刚仔细看了一下,发现这个例子不太合适。换个 Sinatra 中的 Delegator 的实现,主要是证明在 module 中定义类方法并不是没用,而是很有用,具体取决于场景。

https://github.com/sinatra/sinatra/blob/master/lib/sinatra/base.rb#L1976

module中定义类的一个作用就是作为类的namespace

如果没有namespace那还不得天下大乱

#5楼 @lgn21st 你给的例子还是在模块内自用了类方法,通过动态定义方法来缩减重复代码。 这个场景下,使用模块内的类方法是完全没用问题的,我自己曾经也写过这样的代码。 但是在我主题里面的场景下,应该是用class来封装这个方法,而不应该是用module。 就这点,您有什么看法吗。谢谢指教。

#6楼 @kikyous 没错,module还有一个重要的用处就是 命名空间了。

#7楼 @sennmac 我反复阅读你的主题,但是仍然认为你不是在描述一个限定的场景,而是通用场景,基于这个通用场景提出两个结论,在我看来不严谨,所以我选择了一个角度 模块的类方法不是没用的 来反驳。

如果换个角度,我会选择 模块不仅仅只是用来 Mixin 的,比如当我们想要求平方根的时候,我们可以用 Math.sqrt,这样的场景就是把类方法定义在模块中,当作 Utility 来用。

ruby本来就有点反对规范的意思

module的两个作用一个是namespace,一个是mixin,如果是module with class method 可以理解为加了namespace global function,如果没有module那不就是global function了吗 Math.sqrt

倘若你program和内部的instance variable无关,无须实例化,我觉得没必要放在class里,当然放在class也没有问题 class就是继承module的,放class就等于放在module里了,其次java就是通过把class method封装在class里的来实现类似的裸function机制,当然java是没有module的概念的

#9楼 @lgn21st Math.sqrt是一个极好的打我脸的例子.. 看样子一直以来,是我对Utility的定义过于沉重了.. 多谢,多谢。 @cunheise 我个人开始比较反对这种namespace global function.. 总觉得通过模块(一组方法/变量/常量的集合体,非常的轻)上调用方法极其的别扭.. 后来转念一想..模块不也就是个实例(Module类的)吗.. 顿时就释然了..

#10楼 @lithium4010 我的理解是保证代码可读性和概念一致性上,需要一些规范。

#12楼 @sennmac 不要上升到打脸嘛,讨论技术本来就是一件很愉快的事情,跟你讨论的过程也是我梳理概念,查找资料和学习的过程。

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