先看一道题,这道题是codewars上的一道题,我很早就看到了,但是不会写。等到又看到这道题的时候,我刚看完元编程那本书,觉得是可以搞定它的时候了。废话不多说,先看这道题,题目最开始是为JavaScript写的,但是也放在了ruby语言里面,这个没有关系。题目内容是有一个类Calc,通过链式方法调用,可以实现加减乘除。如图给的四个例子。数字只有0-9,运算只有加减乘除,而且每个运算只有一个操作符。(可以先不看下面,自己先想一下怎么写)

  首先,每一个例子都是同样的结构---类名和四个方法。拿第一个例子来举例,ruby中调用一般都是 对象.方法的形式。那么初步的思路就是Calc类构建一个new方法(当然调用new的时候会自动调用initialize方法,如果只是返回一个实例对象,不用写这个方法),为Calc.new对象构建一个one方法,为Calc.new.one对象构建一个plus方法,为Calc.new.one.plus对象构建一个two方法。

这样用单例方法好像没有什么问题,虽然可能会复杂一些,但是应该是能做出来的。那怎么写呢?(其实我也不知道,要是有思路求指教)

我的思路是类似下面的,请看代码

 class A
def one
def self.plus
def self.one
p "one+plus+one"
end
self
end
self
end
end

现在的问题就是把方法名用变量来代替,但是这样的话参数怎么传进去呢?这就是个问题了。于是这种想法就搁浅了。

关于方法嵌套定义的问题,参见http://blog.csdn.net/kiwi_coder/article/details/8122085,讲的很清楚。

一种方法不通就是另一种方法了。在上一种方法中,由于我忘记返回值为self。因此经常出现nil没有方法的错误。于是就想到了method_missing。ruby中的method_missing就是在这个对象没有某个方法的时候,会到method_missing中去找解决方案。method_missing方法正好是把方法名当成参数,于是就可以直接调用了。

代码如下:

 class Calc
# Implement here
3  @@str=""
4  @@time = 0
5  def method_missing(name)
6    has = { :one => 1,:two=>2,:three => 3,:four=>4,:five => 5,
7      :six=>6,:seven => 7,:eight=>8,:nine => 9,:zero=>0,} 9    mth ={:plus=>"+",:minus=>"-",:times=>"*",:divided_by=>"/"}
10    @@str = "" if @@time == 3
11    @@str << has[name].to_s if has.has_key?(name)
12    @@str << mth[name] if mth.has_key?(name)
13    @@time += 1
14    @@time -= 3 if @@time > 3
15    if @@time == 3
16      eval @@str
17    else
18      self
19    end
20  end
end

把方法名传入method_missing的时候,先定义两个hash,然后把方法名对应的值写到一个类变量字符串@@str中,最后用eval执行字符串。@@time是用来计算方法个数,每进行一个运算,字符串清空。值得注意的是:如果不执行的时候,要返回self。

这段代码是我提交的代码,仅仅是完成了功能,但是写的不好。

不足之处:

1使用了eval,这个方法是各种书中不推荐的

2其实两个hash可以合并,这个问题不大。

3我的这个方法只是把方法名合并成字符串,有点投机取巧,而且不能适合更多的运算。

提交之后,看了别人的代码。拿出一个推荐最多的和大家分享。

代码如下:

 # Chainable:
# Calc.new.one.plus.one.plus.one == 3 class Fixnum
def plus; Calc.new("+", self) end
def minus; Calc.new("-", self) end
def times; Calc.new("*", self) end
def divided_by; Calc.new("/", self) end
end class Calc
def initialize(*arguments)
if arguments.length == 2
@operation = arguments[0]
@number = arguments[1]
end
end %w(zero one two three four five six seven eight nine).each_with_index do |w,i|
define_method(w) { perform i }
end def perform number
if @operation
@number.send(@operation, number)
else
number
end
end
end

简单分析一下,4-9行在Fixnum类中定义了加减乘除,并且返回Calc的对象,带着两个参数。12-17行是初始化过程。19-21行定义了0-9的对应方法,每个方法内容都是执行perform方法。23-29行定义了perform方法。拿Calc.new.one.plus.two来解释,Calc.new,不带参数,所以返回Calc的一个实例对象。Calc.new.one,调用实例方法one,

执行perform 1,此时@operation没有值,因此返回number的值1。Calc.new.one.plus,1是Fixnum类的实例,调用plus方法,返回了一个Calc.new的对象,并且带有两个参数。因此给@operation和@number分别赋值为'+',1(这里的self就是1)。Calc.new对象又调用two方法,此时有了@operation,因此执行if条件语句里的内容,得到结果3。

这种方法还可以执行更长的方法,例如Calc.new.one.plus.two.minus.three。

总结一下:链式访问要把每一个方法的对象都弄清楚,每一个方法的返回值是下一个方法的对象。

ruby中的链式访问和方法嵌套的更多相关文章

  1. JavaScript中的链式调用

    链模式 链模式是一种链式调用的方式,准确来说不属于通常定义的设计模式范畴,但链式调用是一种非常有用的代码构建技巧. 描述 链式调用在JavaScript语言中很常见,如jQuery.Promise等, ...

  2. 模拟jquery链式访问

    一直写代码写代码,博客都快荒废了,眼看一月要过完,不能不留下点记忆,嘿嘿,刚研究了下jquery的链式访问,这么好用的技能我赶紧get了下,研究后略微修改,模拟一个简单的链式访问,下面这段代码支持修改 ...

  3. 编程中的链式调用:Scala示例

    编程中的链式调用与Linux Shell 中的管道类似.Linux Shell 中的管道 ,会将管道连接的上一个程序的结果, 传递给管道连接的下一个程序作为参数进行处理,依次串联起N个实用程序形成流水 ...

  4. Java 中的链式编程

    前言 ​ 在写项目的时候,有一个实体类有好多个属性,new 出来之后需要不停的使用setXXX( )方法,效率低而且代码可读性差,查询了下发现可以实现实体类的链式编程. public class Us ...

  5. 由表单验证说起,关于在C#中尝试链式编程的实践

    在web开发中必不可少的会遇到表单验证的问题,为避免数据在写入到数据库时出现异常,一般比较安全的做法是前端会先做一次验证,通过后把数据提交到后端再验证一次,因为仅仅靠前端验证是不安全的,有太多的htt ...

  6. 如何在Objective-C中实现链式语法

    在接触到开源项目 Masonry 后,里面的布局约束的链式写法让我颇感兴趣,就像下面这样: 1 2 3 4 5 6 7 8 UIEdgeInsets padding = UIEdgeInsetsMak ...

  7. java中的链式编程

    听到链式编程听陌生的,但是写出来就感觉其实很熟悉 package test; public class Test { String name; String phone; String mail; S ...

  8. 如何在Objective-C中实现链式语法?

    在接触到开源项目 Masonry 后,里面的布局约束的链式写法让我颇感兴趣,就像下面这样: 1 2 3 4 5 6 7 8 UIEdgeInsets padding = UIEdgeInsetsMak ...

  9. java开发中的链式思维 —— 设计一个链式过滤器

    概述 最近在弄阿里云的sls日志服务,该服务提供了一个搜索接口,可根据各种运算.逻辑等表达式搜出想要的内容.具体语法可见https://help.aliyun.com/document_detail/ ...

随机推荐

  1. 学习:record用法

    详情请参考官网:http://www.erlang.org/doc/reference_manual/records.html http://www.erlang.org/doc/programmin ...

  2. MySQL的外键约束:Cascade/Restrict/No action/SET NULL :级联操作

    转自:http://blog.csdn.net/cnjsnt_s/article/details/5548280 具体使用时需要参考:http://blog.csdn.net/codeforme/ar ...

  3. linux基础教程---内容操作

    一.寻找文件里的指定内容 寻找文件里的指定内容,输出内容所在行的所有信息 grep    被搜索内容    文件路径名 >grep     var       passwd       //在 ...

  4. UE4读取配置文件里面的key-value

    在MyProject/Config/DefaultGame.ini配置文件中添加 [RamaUDP]listenPort=2017PrintLog=false C++代码读取 int32 listen ...

  5. instance method '*****' not found (return type defaults to 'id')

    博文转载至 http://blog.csdn.net/cerastes/article/details/38025801 return type defaultsnot foundiOSwarning ...

  6. 2、Android自己的下拉刷新SwipeRefreshLayout--样式2

    <android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/ ...

  7. std::lock_guard

    /* std::lock_guard:更方便线程对于互斥量的上锁操作 std::lock_guard:在定义一个lock_guard时上锁,保证在析构或者异常时解锁 */ #include <i ...

  8. 关于python类型创建、反射(自醒)与反序列化

    一.反序列化漏洞与新式类 在pickle和cPickle以及shelve这三个序列化类中,想要构造反序列化漏洞执行命令或者代码,都需要用到新式类. shelve其实底层就是调用的pickle和cPic ...

  9. 【黑金原创教程】【Modelsim】【第四章】激励文本就是仿真环境

      声明:本文为黑金动力社区(http://www.heijin.org)原创教程,如需转载请注明出处,谢谢! 黑金动力社区2013年原创教程连载计划: http://www.cnblogs.com/ ...

  10. Windows 2012 Server评估版本安装问题处理

    由于工作需要,在微软官方网站下载了一个Windows2012评估版本,地址:http://technet.microsoft.com/zh-cn/evalcenter/hh670538.aspx 在通 ...