Ruby Ruby 不讲究切面编程吗?

ruohanc · 2012年08月01日 · 最后由 JiangYongKang 回复于 2017年12月18日 · 5549 次阅读

最近刚刚知道 AOP 这个东西, 了解不深入, 不过觉得这个对于一个应用里面打 log 是种不错的方法, 但是似乎在 ruby 里面并没有特别提及这种方式? 大家有没有什么比较不错的实践?

顺便一提的是 AOP 在 python 里面似乎特别容易实现.

PSS: Stack overflow 上面的一个 Ruby 实现方案 挺不错的

Rails 插件不都是用的这种方式么

#1 楼 @hooopo ..我说的是 ruby 嘛....没说 Rails

ruby 一两行代码能实现,没有必要特别提出来 不像 java,实现这样的功能,需要一大堆库,一个简单的功能就这么复杂

如果确定想深入了解 ruby 的 AOP,觉得可以看看ActiveSupport::Callbacks的使用及实现.

python 用 decorator. ruby 直接 alias.

1.9.3-p194 :001 > def cool
1.9.3-p194 :002?>   puts "cool"
1.9.3-p194 :003?> end
 => nil 
1.9.3-p194 :004 > alias :not_bad :cool
 => nil 
1.9.3-p194 :005 > def cool
1.9.3-p194 :006?>   puts "log in not bad"
1.9.3-p194 :007?>   not_bad
1.9.3-p194 :008?> end
 => nil 
1.9.3-p194 :009 > cool
log in not bad
cool
 => nil 

#4 楼 @Saito 嗯..这个是最简单的..不过不能跑两次嘛....

我是在想有没有成熟稳定的 gem 或者在 std-lib 里面就有这样的东西?

#4 楼 @Saito 也可以用继承或 alias_method_chain

[1] pry(main)> class Cool
[1] pry(main)*   def say
[1] pry(main)*     puts "cool"
[1] pry(main)*   end  
[1] pry(main)* end  
=> nil
[2] pry(main)> class CoolWithLog < Cool
[2] pry(main)*   def say
[2] pry(main)*     super
[2] pry(main)*     puts "log it"
[2] pry(main)*   end  
[2] pry(main)* end  
=> nil
[3] pry(main)> CoolWithLog.new.say
cool
log it

#5 楼 @ruohanc 3 楼说的 activesupport callbacks 就是成熟稳定的啊 Rails 里用的

#7 楼 @hooopo 嗯..我晚上看看...

不过不应该吧..只有一种 gem? 我在写 ruby 脚本的时候可能不想搞进 AS 这么大的东西挖..

#8 楼 @ruohanc require 'active_support/callbacks'

#3 楼 @cxh116 是啊,Java 是静态语言,因为有了反射这种偏动态语言的特性才搞出个 ‘Spring’,然后 Javaer 像发现银弹一样,到处鼓吹 AOP。AOP 的确为解决 security, transactions, and logging 这类问题带来了很大方便。 其实 AOP 的实质也就是可以动态改变对象的生命周期,也就是改变原来方法的形为。Ruby 一个 alias 就很容易搞定了,没必要强调 AOP 这个概念。

java 里面的各种设计模式在 ruby 里面在语言层面就已经解决了。 比如 Iterator,比如 Mixin,比如 Singleton,比如 Observer...

像日志这种用 AOP 做示例能够解决的需求,都是伪需求,以前写 Java 的时候,写过的 AOP Logging,现在回头看看都是玩具。

#11 楼 @quakewang ruby 的优点对于没学过 java 等语言的人来说真的很难想象

用过 ruby,回来写基于 j2ee 框架的 java 代码,感觉各种限制,各种繁琐。静态语言伤不起呀

看完这个帖子后,令我重新回忆起当初用 Java 时的感觉,什么 AOP、依赖注入

后来学了 Ruby,感觉就是那班学院派 Javaer 忙着搞一堆炫目的理论,然后 Rubyist 什么都不管,只喝着咖啡写几行代码

😏

我上过官方的 Spring 培训,AOP 方面,主推在线性能测试切片。使用场景是有的,AOP 的目的还是方便切入方法,方便测试,调优。java 开发还是应该把重心放在业务逻辑上,当需要切入时,用 Spring 的反转 +AOP 就可以对在线的应用切入调优。Ruby 肯定提供不了这个,但也不需要。

应用 AOP 的场景一定是比较重要的中间件模块代码,没法下线,并且还不让开发接触生产服务器。咋办,只能 AOP 啦。

#11 楼 @quakewang 嗯..那我问问日志怎么写比较好呢.?

#9 楼 @hooopo 我看过这个啦, 似乎这个用法对原类的修改太大了, 需要代理的方法还要加上 run_callbacks, 使用前还要加上 define_callbacksset_callback

#10 楼 @camel but 我是看到 python 里面解决这个问题特别的方便, 只要在方法前面加上一行 @callback_method_name 就行了

好吧..其实我发现我的问题只有一个了...就是怎么在 ruby 代码里面方便的做 profile 和打 log

看半天完全不知道你们在讲啥... 后来看 so 里面的例子, 终于看明白了. 真 Cool !!! 不过后面那一段有点太灵活太繁琐了. block 套 block ,又使用 block 来定义方法对象, block.call 竟然又返回一个 block, Oh, My God. 看着晕.

Ruby 天生就支持 AOP。


class Game
  def play
    puts 'play'
  end
end

class Game
  alias_method :old_play, :play
  def play
    old_play
    puts 'log'
  end
end

Game.new.play

# play
# log

#19 楼 @ery 这个栗子 #3 楼@Saito 举过了。。我说这个栗子的缺点是你不能再次 alias_method :old_play, :play,这样很显然会有 stack level too deep 异常

#16 楼 @ruohanc 如果用 Java 的 AOP profile log 例子来对应,简化后的 ruby 代码如下:

class Object
  def self.profile(method)
    _prof_method = "prof_#{method}".to_sym
    alias_method _prof_method, method

    self.send(:define_method, method.to_s) do |*args|
      start = Time.now
      result = self.send(_prof_method, *args)
      p "#{method} runs " + (Time.now - start).to_s
      return result
    end
  end
end

然后你给需要做 profile 的方法声明一下:

class Hello
   def world
    p "world"
  end

  profile :world
end

如果你想要做得更容易调用,不想侵入 Object root class,就用 module/include 的 mixin 方式来做。 如果你想运行期间添加,就 open class。

不过我还是要多说一句,这种只能用来做玩具例子,实际上要做 profile log 的情景比这个要复杂很多,AOP 不适合做这个。

才知道 alias 就是 AOP..

#21 楼 @quakewang 嗯。那你写 ruby 的时候都不打 log 吗。?

我觉得 ruohanc 是不是没有完全理解 ruby 语言的一些特性,语言和语言之间有很大的差异,是找不到一些特定 terminalogy 的相同 solution。

像这个 AOP,如果非要写,就写出来的是 Java style 的 ruby 了。

#24 楼 @gene_wu 嗯嗯..肯定是这样的...不过我 java 也不熟..只是听同事在说这种模式..而我也正好在写 ruby 的玩意, 的确碰上了打 log 不方便的事情, 所以就在这里问了这个问题..不知道你能给我一个 rubist 的方案么.?

#20 楼 @ruohanc alias_method 第二次 抛出 stack level too deep异常的确是个问题, 如果说要实现的很复杂,我觉得 可以考虑 楼上 #3 楼 @cxh116 的建议 ActiveSupport::Callbacks Log 这个需求,可以考虑观察者模式,也可以用 ActiveRecord::Observer 我们就是用 ActiveRecord::Observer 实现的 log,前提你用的是 Rails。

#27 楼 @hooopo 谢谢你的推荐,看了一下,挺不错的,也是一个不错的选择。

29楼 已删除

把那本 meta programming ruby 好好看看,基本就明白了,AOP 已经在 ruby 骨子里面了...

AOP 是 Java 特色,就和国情是天朝特色一样,好不容易出来了就别再提这个了

想当年为了让开发环境更好用做了大量的改进,那堆框架给我捣了好多乱,结果改进的东西在团队内部的 policy war 里牺牲掉了大部分,可恶心死我了,再也不想用了,他们爱怎么地怎么地,我不管了

我喜歡您在您的文章中提供的有價值的信息。我將書籤您的博客,並定期在這裡再次檢查。我敢肯定我會在這裡學到許多新的東西!在未來的祝你好運!http://theglobaltransition.com/

感謝這樣一個偉大的文章在這裡。我正在尋找這樣的事情相當長的時間,最後我發現它在你的博客。這肯定是有趣的,對我來說,閱讀有關 Web 應用程序及其市場現狀。感謝更多的時間和繼續張貼在不久的將來也不錯的。toys for men

ery 回复

如果方法比较多,分布在各个 controller 或者 service 中怎么办?总不能每个文件中都去写 几个 alias_method😭

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