免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2333 | 回复: 2
打印 上一主题 下一主题

Ruby库中委托Delegator类的实现 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-10-29 20:09 |只看该作者 |倒序浏览
Ruby库中委托Delegator类的实现



委托的模式上一篇偷天换日已经解释,这里只讲解里面的Delegator库的实现.

既然采用ruby,它的库一般来说,用起来会更加funny,更加自然.
如同singleton单例库,你写一个类

Java代码
  1. 1.class Klass   
  2. 2. def method   
  3. 3. end   
  4. 4.end  
  5. class Klass
  6. def method
  7. end
  8. end

  9. 想让它成为单例类,只需:

  10. Java代码  
  11. 1.require 'singleton'  
  12. 2.class Klass   
  13. 3. include Singleton   
  14. 4. def method   
  15. 5. end   
  16. 6.end  
  17. require 'singleton'
  18. class Klass
  19. include Singleton
  20. def method
  21. end
  22. end
复制代码
如此简单,它自动将构造方法置为隐藏,自动加载多线程锁调用,哇,还是线程安全,如果是自己写那得不少代码,而且使用ruby的Module机制,无须继承任何类,毫无副作用...

好了,题外话讲完后,我们来看看Delegator吧.
打开ruby库的delegate.rb文件.
代码行有多少,好家伙,大概330行.除去注释,实际有效代码有100行吧.
第1步看看使用接口先:

Java代码
  1. 1.# SimpleDelegator's implementation serves as a nice example here.   
  2. 2.#   
  3. 3.#    class SimpleDelegator < Delegator   
  4. 4.#      def initialize(obj)   
  5. 5.#        super             # pass obj to Delegator constructor, required   
  6. 6.#        @_sd_obj = obj    # store obj for future use   
  7. 7.#      end   
  8. 8.#   
  9. 9.#      def __getobj__   
  10. 10.#        @_sd_obj          # return object we are delegating to, required   
  11. 11.#      end   
  12. 12.#   
  13. 13.#      def __setobj__(obj)   
  14. 14.#        @_sd_obj = obj    # change delegation object, a feature we're providing   
  15. 15.#      end   
  16. 16.#   
  17. 17.#      # ...   
  18. 18.#    end  
  19. # SimpleDelegator's implementation serves as a nice example here.
  20. #
  21. #    class SimpleDelegator < Delegator
  22. #      def initialize(obj)
  23. #        super             # pass obj to Delegator constructor, required
  24. #        @_sd_obj = obj    # store obj for future use
  25. #      end
  26. #
  27. #      def __getobj__
  28. #        @_sd_obj          # return object we are delegating to, required
  29. #      end
  30. #
  31. #      def __setobj__(obj)
  32. #        @_sd_obj = obj    # change delegation object, a feature we're providing
  33. #      end
  34. #
  35. #      # ...
  36. #    end
复制代码
这就是说只要继承Delegator,然后实现__getobj__与__setobj__方法即可.
这个使用方法在上一篇偷天换日中即用这个方法.
想想也是,如此的接口也很简洁了.
再看如何实现的:

Java代码
  1. 1.class Delegator   
  2. 2.  
  3. 3.  #   
  4. 4.  # Pass in the _obj_ to delegate method calls to.  All methods supported by   
  5. 5.  # _obj_ will be delegated to.   
  6. 6.  #   
  7. 7.  def initialize(obj)   
  8. 8.    #拿到所有类的实例方法,去掉几个   
  9. 9.    #因为Kernel是一个module,它会被所有类包含.可参阅RubyHackGuide进行掌握.   
  10. 10.    preserved = ::Kernel.public_instance_methods(false)   
  11. 11.    preserved -= ["to_s","to_a","inspect","==","=~","==="]   
  12. 12.    for t in self.class.ancestors   
  13. 13.      preserved |= t.public_instance_methods(false)   
  14. 14.      preserved |= t.private_instance_methods(false)   
  15. 15.      preserved |= t.protected_instance_methods(false)   
  16. 16.      break if t == Delegator   
  17. 17.    end   
  18. 18.    preserved << "singleton_method_added"  
  19. 19.    for method in obj.methods   
  20. 20.      # 搜集到所有实例方法,   
  21. 21.      # 以下开始利用eval动态往本代理中添加方法   
  22. 22.      next if preserved.include? method   
  23. 23.      begin   
  24. 24.       # 这里的self是实例本身,不是类,请注意.   
  25. 25.       # 所以定义的方法都是自身可以用,而不是整个委托类.   
  26. 26.       # 异常处理的时候使用了一个的技巧,将委托的异常信息给去掉了,更加透明了...(好阴啊,如果是库出问题了连个跟踪的地儿都找不到)   
  27. 27.    eval <<-EOS   
  28. 28.      def self.#{method}(*args, &block)   
  29. 29.        begin   
  30. 30.          __getobj__.__send__(:#{method}, *args, &block)   
  31. 31.        rescue Exception   
  32. 32.          $@.delete_if{|s| /:in `__getobj__'$/ =~ s} #`   
  33. 33.          $@.delete_if{|s| /^\\(eval\\):/ =~ s}   
  34. 34.          Kernel::raise   
  35. 35.        end   
  36. 36.      end   
  37. 37.    EOS   
  38. 38.      rescue SyntaxError   
  39. 39.        raise NameError, "invalid identifier %s" % method, caller(4)   
  40. 40.      end   
  41. 41.    end   
  42. 42.  end   
  43. 43.  alias initialize_methods initialize   
  44. 44.  
  45. 45.  # 这个method_missing是重新实现是怕被委托的那小子动态添加方法,那'我'(委托类)不能不支持啊,所以添加在这里.   
  46. 46.  # 那我想问原作者,你上述的实现期不多余了,就只为能再透明点啊...   
  47. 47.  # Handles the magic of delegation through \_\_getobj\_\_.   
  48. 48.  def method_missing(m, *args)   
  49. 49.    target = self.__getobj__   
  50. 50.    unless target.respond_to?(m)   
  51. 51.      super(m, *args)   
  52. 52.    end   
  53. 53.    target.__send__(m, *args)   
  54. 54.  end   
  55. 55.  
  56. 56.  #   
  57. 57.  # Checks for a method provided by this the delegate object by fowarding the   
  58. 58.  # call through \_\_getobj\_\_.   
  59. 59.  #   
  60. 60.  def respond_to?(m)   
  61. 61.    return true if super  
  62. 62.    return self.__getobj__.respond_to?(m)   
  63. 63.  end   
  64. 64.  
  65. 65.  #   
  66. 66.  # This method must be overridden by subclasses and should return the object   
  67. 67.  # method calls are being delegated to.   
  68. 68.  #   
  69. 69.  # 你继承了后老实实现它吧.   
  70. 70.  def __getobj__   
  71. 71.    raise NotImplementedError, "need to define `__getobj__'"  
  72. 72.  end   
  73. 73.  
  74. 74.  # 这些为了可以使用marshal进行外部类存储.   
  75. 75.  # 如果不使用它,完全不用理会.   
  76. 76.  # Serialization support for the object returned by \_\_getobj\_\_.   
  77. 77.  def marshal_dump   
  78. 78.    __getobj__   
  79. 79.  end   
  80. 80.  # Reinitializes delegation from a serialized object.   
  81. 81.  def marshal_load(obj)   
  82. 82.    initialize_methods(obj)   
  83. 83.    __setobj__(obj)   
  84. 84.  end   
  85. 85.end  
  86. class Delegator

  87.   #
  88.   # Pass in the _obj_ to delegate method calls to.  All methods supported by
  89.   # _obj_ will be delegated to.
  90.   #
  91.   def initialize(obj)
  92.     #拿到所有类的实例方法,去掉几个
  93.     #因为Kernel是一个module,它会被所有类包含.可参阅RubyHackGuide进行掌握.
  94.     preserved = ::Kernel.public_instance_methods(false)
  95.     preserved -= ["to_s","to_a","inspect","==","=~","==="]
  96.     for t in self.class.ancestors
  97.       preserved |= t.public_instance_methods(false)
  98.       preserved |= t.private_instance_methods(false)
  99.       preserved |= t.protected_instance_methods(false)
  100.       break if t == Delegator
  101.     end
  102.     preserved << "singleton_method_added"
  103.     for method in obj.methods
  104.       # 搜集到所有实例方法,
  105.       # 以下开始利用eval动态往本代理中添加方法
  106.       next if preserved.include? method
  107.       begin
  108.        # 这里的self是实例本身,不是类,请注意.
  109.        # 所以定义的方法都是自身可以用,而不是整个委托类.
  110.        # 异常处理的时候使用了一个的技巧,将委托的异常信息给去掉了,更加透明了...(好阴啊,如果是库出问题了连个跟踪的地儿都找不到)
  111.         eval <<-EOS
  112.           def self.#{method}(*args, &block)
  113.             begin
  114.               __getobj__.__send__(:#{method}, *args, &block)
  115.             rescue Exception
  116.               $@.delete_if{|s| /:in `__getobj__'$/ =~ s} #`
  117.               $@.delete_if{|s| /^\\(eval\\):/ =~ s}
  118.               Kernel::raise
  119.             end
  120.           end
  121.         EOS
  122.       rescue SyntaxError
  123.         raise NameError, "invalid identifier %s" % method, caller(4)
  124.       end
  125.     end
  126.   end
  127.   alias initialize_methods initialize

  128.   # 这个method_missing是重新实现是怕被委托的那小子动态添加方法,那'我'(委托类)不能不支持啊,所以添加在这里.
  129.   # 那我想问原作者,你上述的实现期不多余了,就只为能再透明点啊...
  130.   # Handles the magic of delegation through \_\_getobj\_\_.
  131.   def method_missing(m, *args)
  132.     target = self.__getobj__
  133.     unless target.respond_to?(m)
  134.       super(m, *args)
  135.     end
  136.     target.__send__(m, *args)
  137.   end

  138.   #
  139.   # Checks for a method provided by this the delegate object by fowarding the
  140.   # call through \_\_getobj\_\_.
  141.   #
  142.   def respond_to?(m)
  143.     return true if super
  144.     return self.__getobj__.respond_to?(m)
  145.   end

  146.   #
  147.   # This method must be overridden by subclasses and should return the object
  148.   # method calls are being delegated to.
  149.   #
  150.   # 你继承了后老实实现它吧.
  151.   def __getobj__
  152.     raise NotImplementedError, "need to define `__getobj__'"
  153.   end

  154.   # 这些为了可以使用marshal进行外部类存储.
  155.   # 如果不使用它,完全不用理会.
  156.   # Serialization support for the object returned by \_\_getobj\_\_.
  157.   def marshal_dump
  158.     __getobj__
  159.   end
  160.   # Reinitializes delegation from a serialized object.
  161.   def marshal_load(obj)
  162.     initialize_methods(obj)
  163.     __setobj__(obj)
  164.   end
  165. end
复制代码
所有的解析在上面的注释里了.
这里需要你的ruby技术相当熟练,掌握ruby元编程技能.因能力有限,欢迎就不同的观点进行探讨.
写在这里后,据松本行弘说forwardable模块更加优秀.有时间可以再研究下.
最后抱怨一下,ruby库的测试不完善啊,偶尔会出现一些问题,还需要进行猴子补丁..

论坛徽章:
0
2 [报告]
发表于 2011-11-01 14:47 |只看该作者
ruby技术相当熟练

论坛徽章:
0
3 [报告]
发表于 2011-11-02 06:24 |只看该作者
ruby技术相当熟练
cinanine 发表于 2011-11-01 14:47



    你?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP