Ruby ruby 如何实现这个 aop 效果?

chenge · 发布于 2012年11月11日 · 最后由 chenge 回复于 2016年7月04日 · 4553 次阅读
4215

这个是spring python的例子,看上去还不错。

import springpython.aop as saop

class SampleService:
    def method(self, data):
        return "You sent me '%s'" % data

    def m2(self, data):
        return "You sent me 2'%s'" % data

class WrappingSvc(saop.MethodInterceptor):
    def invoke(self, invocation):
        return "Wrapped:" + invocation.proceed() + ":Wrapped"


service = saop.ProxyFactoryObject(target = SampleService(), interceptors =  [WrappingSvc()])

print service.method("something")
print service.m2("something")

Wrapped:You sent me 'something':Wrapped Wrapped:You sent me 2'something':Wrapped

共收到 39 条回复
244

奇怪,为什么没人给答案呢?嫌简单懒得回答?

96

这个怎么看着不像Python ...

Python的风格难道不该是像下面这样


def m1():
    return "m1"

def m2():
    return "m2"

def wrapped(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        return "<wrapped>{}</wrapped>".format(func(*args, **kwargs))

print m1()
print m2()

m1 = wrapped(m1)
m2 = wrapped(m2)

print m1()
print m2()
202

@fsword 第一,楼主提到的springpyhton不是每个人都熟悉,第二,今天双11,被你厂的黑猫商城搞的大家都很忙,实在没空管这些一看看不明白的帖子。

2110

这个算不算

class SampleService
  def m1(data)
    return "You sent me '#{data}'"
  end
  def m2(data)
    return "You sent me 2'#{data}'"
  end
end

class Wrapping
  def initialize(target)
    @target = target
  end

  def method_missing(m, *args)
    return "Wrapped:#{@target.send(m, *args)}:Wrapped"
  end
end

wrap = Wrapping.new(SampleService.new)
p wrap.m1("something")
p wrap.m2("something")
4215

#4楼 @cwheart 基本接近了,思路很巧妙,这个对单个aspect够用。 那个python似乎可以串接多个aspect,这个估计用的不多。

3479

这个怎么看起来有点像tornado

2110

#5楼 @chenge aspect是神马?写个串接多个的例子

188

这不是 decorator 嘛?-__,-

https://github.com/fredwu/ruby_decorators

class Hi < RubyDecorator
  def call(this, *args, &blk)
    this.call(*args, &blk).sub('hello', 'hi')
  end
end

class Batman < RubyDecorator
  def call(this, *args, &blk)
    this.call(*args, &blk).sub('world', 'batman')
  end
end

class Catwoman < RubyDecorator
  def initialize(*args)
    @args = args.any? ? args : ['catwoman']
  end

  def call(this, *args, &blk)
    this.call(*args, &blk).sub('world', @args.join(' '))
  end
end

class World
  extend RubyDecorators

  def initialize
    @greeting = 'hello world'
  end

  def hello_world
    @greeting
  end

  +Batman
  def hello_batman
    @greeting
  end

  +Hi
  +Catwoman
  def hello_catwoman
    @greeting
  end

  +Catwoman.new('super', 'catwoman')
  def hello_super_catwoman
    @greeting
  end
end

world = World.new

world.hello_world          # => "hello world"
world.hello_batman         # => "hello batman"
world.hello_catwoman       # => "hi catwoman"
world.hello_super_catwoman # => "hello super catwoman"
4215

aspect是一种新的编程范型,已经有多年历史了,大型程序比较有用。主要用途是横切,比如常见的log,安全,缓存,事务等可以写到aspect里面。spring框架就是靠这个成名。

rubu要写多个串接的估计也不容易。

2110

#9楼 @chenge 就是spring的AOP呗,负责任的告诉你,实现起来很容易,很多种方式

4215

#10楼 @cwheart show一下代码,如果真的很容易,那恭喜你,可以抢spring的饭碗了。

2110

#11楼 @chenge 抢饭碗不敢

class SampleService
  def m1(data)
    return "You sent me '#{data}'"
  end
  def m2(data)
    return "You sent me 2'#{data}'"
  end
end

class Wrapping
  def initialize(target, wrappers = [])
    @target = target
    @wrappers = wrappers
  end

  def method_missing(m, *args)
    return "#{@wrappers.map(&:perform_befor).join(':')}:#{@target.send(m, *args)}:#{@wrappers.map(&:perform_after).join(':')}"
  end
end

class WrapperDemo1
  def perform_befor
    "demo1 befor"
  end

  def perform_after
    "demo1 after"
  end
end

class WrapperDemo2
  def perform_befor
    "demo2 befor"
  end

  def perform_after
    "demo2 after"
  end
end

wrap = Wrapping.new(SampleService.new, [WrapperDemo1.new, WrapperDemo2.new])
p wrap.m1("something")
p wrap.m2("something")
4215

#12楼 @cwheart 效果不错。你的ruby水平很好。一点建议,那个长语句可重构下,可读性会好些。

2110

#13楼 @chenge 这个是基础,谈不上水平,只能说动态语言比较灵活

146

#12楼 @cwheart 最好让 Wrapping 继承 BasicObject :)

class Wrapping < BasicObject
4215

#12楼 @cwheart 代码还有点问题,顺序应该是:

before1 before2 method after2 after1

不过,不严格的情况下,似乎是可以的。

146

#16楼 @chenge 1.9.x 下 BasicObject 可做blank class 用。1.8.x 需要自己处理一下,或使用gem "blankslate"。

Ruby 的文档已经说的详细了 :) http://ruby-doc.org/core-1.9.3/BasicObject.html

4215

#18楼 @skandhas 这个不是很重要吧。

146

#19楼 @chenge 是重要的。blank class 的作用主要是防止名字空间被污染。 以此例来说,Wrapping 默认是从 Object 继承,这样会导致 Wrapping.new 创建的对象拥有来自Object 及 Kernel 的方法。作为一个代理对象,这有可能会与被代理的对象有方法的冲突。 所以,在实现类似的代理类时,通常的做法是让它继承一个blank class。

比如还是以此例稍微修改一下,然后你看看结果

class SampleService
  def m1(data)
    return "You sent me '#{data}'"
  end
  def m2(data)
    return "You sent me 2'#{data}'"
  end
  def method(data)
     return "You sent me 3'#{data}'"
  end
end

...省略......

p wrap.m1("something")
p wrap.m2("something")
p wrap.method("something")
4215

#20楼 @skandhas 但是这样的话,就不能使用kernel了,这个要权衡吧。

146

#21楼 @chenge 是有使用场合的,主要是用在写代理类上。其他大多数的场合还是默认继承 Object

2880

我写了这么多年代码还没发现过这样做的必要...

244

#3楼 @xds2000 其实我是想说,什么 springpython 真是侮辱 python 了,python 的 decorate 甚至比 ruby 都好用,作者居然迁移java框架,就象已经修建了铁路,却非要找几匹马来拉火车一样,简直是上等的吐槽贴啊

#11楼 @chenge 在ruby(和其它动态语言)社区,spring这种东西本来就没有饭碗

94

有这样用Python的?

2831

看不懂啊,这不就是一个简单 的mixin功能吗? 哦 其实是个 decorator

class SampleService
  def meth(data)
    "You sent me #{data}" 
  end

  def m2(data)
    "You sent me 2#{data}"
  end
end

class Wrapper
  def invoke(&blk)
    "Wrapped: " + blk.call + " :Wrapped" if block_given?
  end
end

module Decorator
  def initialize(service, wrap)
    @service = service
    @wrap = wrap
  end

  def method_missing(meth, *args)
    if @service.respond_to?(meth)
       @wrap.invoke { @service.send(meth, *args) } 
    else
      super
    end
  end

  def respond_to?(meth)
    @service.respond_to?(meth)
  end
end

class Service
  include Decorator
end

service = Service.new(SampleService.new, Wrapper.new)

puts service.meth("something")
puts service.m2("something")
4215

#26楼 @xuluan 装饰模式确实更好,可以级联多个。

4215

#24楼 @fsword 能否给出python代码,大家学习下。

244

#28楼 @chenge python我只是票友,不过 #2楼 @bhuztez 已经给出答案了。另外(如果没看过的话),我推荐 ruby设计模式 这本书

2963

看这个包的命名应该是代理模式 用 C++ 都可以实现这种模式……

146

#23楼 @luikore blank class 在写 builder-style 的 DSL 时,经常会用到。比如gem “builder” 和 DHH 的 “jbuilder”

4215

#30楼 @wuwx 严格说应是代理模式。两个模式的图不一样,装饰更难理解一些。

96

每次看这种python/ruby写java就抓鸡心疼

465

本来静态语言当宝的各种设计模式要解决的问题,在动态语言的鸭子和匿名闭包等特性下都不是问题…

96
class World
  extend RubyDecorators

  def initialize
    @greeting = 'hello world'
  end

  def hello_world
    @greeting
  end

  +Batman
  def hello_batman
    @greeting
  end

  +Hi
  +Catwoman
  def hello_catwoman
    @greeting
  end

  +Catwoman.new('super', 'catwoman')
  def hello_super_catwoman
    @greeting
  end
end

这里的+Hi , + 号是什么意思?

244

#36楼 @donbe 直接去看源码啊,很简单的

class RubyDecorator
  def self.+@
    RubyDecorators::Stack.all << self
  end

  def +@
    RubyDecorators::Stack.all << self
  end
end
3659

#36楼 @donbe 双飞燕那本书里也有类似例子

1031

对这种问题无爱呀. 只会让我更混乱....

还是用 Ruby 的方式解决 Ruby 自己擅长的问题吧. 何必要和其他类比??

4215 chenge Ruby 学习汇集,请推荐内容 中提及了此贴 7月04日 11:35
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册