define_method跟def

今天稍微搜了一下很少有讲define_method跟def的中文文章,英文的也没有讲得很明白的,今天就斗胆把我的理解跟大家分享一下。 

入门级别: 
Ruby代码   收藏代码
  1. class Foo  
  2.     def initialize x  
  3.         @x = x  
  4.     end  
  5. end  
  6.   
  7. class Bar  
  8.     define_method :initialize do |x|  
  9.         @x = x  
  10.     end  
  11. end  

这两段代码的功能是完全一样的,但是用benchmark比较一下,明显是def要快。 
Ruby代码   收藏代码
  1. require 'benchmark'  
  2.   
  3. Foo = Class.new  
  4. Bar = Class.new  
  5.   
  6. t = 100000  
  7.   
  8. Benchmark.bm do |x|  
  9.     x.report('def') {t.times {Foo.class_eval {def a;end}}}  
  10.     x.report('define_method') {t.times {Bar.class_eval {define_method(:a){}}}}  
  11. end  


所以第一个结论就是,def, define_method都可以的时候,用def最好了。 

现在我们从语法上来分析第一段代码:def是ruby为数不多的关键字之一(连 + = * / new都不是ruby的关键字,你敢信?),def就是用来定义方法的,没什么能展开讲的了。但是define_method不一样,define_method是一个方法,这个方法的作用是产生一个新方法(方法如其名)。 

define_method是一个方法,方法就有参数,define_method的参数就是要生成的方法名,所以define_method比def聪明的地方就是他可以根据参数动态的生成很方法! 

入第二个门级别: 
Ruby代码   收藏代码
  1. method_name = ''  
  2. puts 'Type "exit" to exit...'  
  3.   
  4. class SmartClass  
  5.   
  6.     def self.method_added method_name  
  7.         puts "New Method: #{method_name.chomp} has been created."  
  8.     end  
  9.   
  10. end  
  11.   
  12. while method_name.chomp != 'exit'  
  13.     method_name = gets  
  14.     SmartClass.class_eval do  
  15.         define_method(method_name) {}  
  16.     end  
  17. end  


这段代码中method_added是一个钩子方法(Hook),方法如其名(方法不如其名的话名字起得是要多滥),每当有新方法添加到SmartClass的时候他都会大叫一声。 

运行一下,果真我们的SmartClass能根据我们的输入动态的创建方法了! 

当然这不是最重要的区别。最重要的区别是:define_method能共享上下文的作用域! 
Ruby代码   收藏代码
  1. class ShabbyClass  
  2.       
  3.     my_name = 'piecehealth'  
  4.   
  5.     def say_my_name  
  6.         puts my_name  
  7.     end  
  8. end  
  9.   
  10.   
  11. class SmartClass  
  12.       
  13.     my_name = 'piecehealth'  
  14.   
  15.     define_method :say_my_name do  
  16.         puts my_name  
  17.     end  
  18. end  
  19.   
  20.   
  21. SmartClass.new.say_my_name  # piecehealth  
  22. ShabbyClass.new.say_my_name # NameError  


def中的代码是跟上下文完全隔离的(只认识带@跟美刀的变量),my_name这个变量是读不到。而define_method就显得更加open一点,乐意结识不带任何修饰的小伙伴(变量my_name),而这个特点,将会在动态生成一些方法是变得非常常见。 


Ruby代码   收藏代码
  1. class Company  
  2.       
  3.     attr_accessor :service_tel  
  4.   
  5.     def initialize name, service_tel   
  6.         @name = name  
  7.         @service_tel = service_tel  
  8.     end  
  9.   
  10.     def release_new_product product_name  
  11.         product = Object.const_set(product_name.capitalize, Class.new)  
  12.         company = self  
  13.         product.class_eval do  
  14.             define_method :initialize do  
  15.                 @name = product_name  
  16.                 @company = company  
  17.             end  
  18.   
  19.             attr_reader :company  
  20.   
  21.         end  
  22.     end  
  23.   
  24. end  
  25.   
  26.   
  27. apple = Company.new('Apple''123-1234567')  
  28. apple.release_new_product('iPhone32z')  
  29.   
  30. ip32z = Iphone32z.new  
  31. p ip32z # #<Iphone32z:0x25d2d70 @name="iPhone32z", @company=#<Company:0x25d3028 @name="Apple", @service_tel="123-1234567">>  
  32. p ip32z.company.service_tel # "123-1234567"  
  33. apple.service_tel = '321-7654321'  
  34. p ip32z.company.service_tel # "321-7654321"  


最后一段代码:一个公司的类Company,每当某个公司发布一个新产品,将自动建立一个新的关于该产品类,并且产品的生产厂商将自动设成它的出场公司,不用加任何多余参数。代码16行的成功读到这个类外面(12行)定义的company信息,使这个过程变得轻松愉快易维护。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
/* * 基于双向链表实现双端队列结构 */ package dsa; public class Deque_DLNode implements Deque { protected DLNode header;//指向头节点(哨兵) protected DLNode trailer;//指向尾节点(哨兵) protected int size;//队列中元素的数目 //构造函数 public Deque_DLNode() { header = new DLNode(); trailer = new DLNode(); header.setNext(trailer); trailer.setPrev(header); size = 0; } //返回队列中元素数目 public int getSize() { return size; } //判断队列是否为空 public boolean isEmpty() { return (0 == size) ? true : false; } //取首元素(但不删除) public Object first() throws ExceptionQueueEmpty { if (isEmpty()) throw new ExceptionQueueEmpty("意外:双端队列为空"); return header.getNext().getElem(); } //取末元素(但不删除) public Object last() throws ExceptionQueueEmpty { if (isEmpty()) throw new ExceptionQueueEmpty("意外:双端队列为空"); return trailer.getPrev().getElem(); } //在队列前端插入新节点 public void insertFirst(Object obj) { DLNode second = header.getNext(); DLNode first = new DLNode(obj, header, second); second.setPrev(first); header.setNext(first); size++; } //在队列后端插入新节点 public void insertLast(Object obj) { DLNode second = trailer.getPrev(); DLNode first = new DLNode(obj, second, trailer); second.setNext(first); trailer.setPrev(first); size++; } //删除首节点 public Object removeFirst() throws ExceptionQueueEmpty { if (isEmpty()) throw new ExceptionQueueEmpty("意外:双端队列为空"); DLNode first = header.getNext(); DLNode second = first.getNext(); Object obj = first.getElem(); header.setNext(second); second.setPrev(header); size--; return(obj); } //删除末节点 public Object removeLast() throws ExceptionQueueEmpty { if (isEmpty()) throw new ExceptionQueueEmpty("意外:双端队列为空"); DLNode first = trailer.getPrev(); DLNode second = first.getPrev(); Object obj = first.getElem(); trailer.setPrev(second); second.setNext(trailer); size--; return(obj); } //遍历 public void Traversal() { DLNode p = header.getNext(); while (p != trailer) { System.out.print(p.getElem()+" "); p = p.getNex
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值