ruby中的链式访问和方法嵌套

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

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

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

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

 1 class A
 2     def one
 3         def self.plus
 4             def self.one
 5                 p "one+plus+one"
 6             end
 7             self
 8         end
 9         self
10     end
11 end

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

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

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

代码如下:

 1 class Calc
 2   # 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,}
 8
 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
21 end

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

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

不足之处:

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

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

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

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

代码如下:

 1 # Chainable:
 2 # Calc.new.one.plus.one.plus.one == 3
 3
 4 class Fixnum
 5   def plus;       Calc.new("+", self) end
 6   def minus;      Calc.new("-", self) end
 7   def times;      Calc.new("*", self) end
 8   def divided_by; Calc.new("/", self) end
 9 end
10
11 class Calc
12   def initialize(*arguments)
13     if arguments.length == 2
14       @operation = arguments[0]
15       @number    = arguments[1]
16     end
17   end
18
19   %w(zero one two three four five six seven eight nine).each_with_index do |w,i|
20     define_method(w) { perform i }
21   end
22
23   def perform number
24     if @operation
25       @number.send(@operation, number)
26     else
27       number
28     end
29   end
30 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中的链式访问和方法嵌套

时间: 2024-12-10 14:30:58

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

java中的链式编程

听到链式编程听陌生的,但是写出来就感觉其实很熟悉 1 package test; 2 3 public class Test { 4 String name; 5 String phone; 6 String mail; 7 String sex; 8 public Test setName(String name) { 9 this.name = name; 10 return this; 11 } 12 public Test setPhone(String phone) { 13 this

在python中实现链式调用

用过jquery的一般都知道在jquery中可以链式调用,代码简洁优雅.比如$("a").addClass("test").show().html("foo");. 在redis-py中的pipeline中也可以链式调用,比如pipe.set('foo', 'bar').sadd('faz', 'baz').incr('auto_number').execute() . 那么究竟怎么实现的呢? 很简单,返回对象自己就行了,即return self

定义在方法中的内部类能否访问该方法的局部变量?

定义在方法中的内部类当然是可以访问方法中的局部变量的,访问的方法就是在局部变量上添加final关键字 (1)内部类是外部类的一个成员,就像外部类的成员方法一样,所以内部类有权限访问外部类的所有成员,包括private的.(2)内部类不能访问外部类方法中的局部变量,除非变量是final的(一般发生在方法中定义的内部类).这是因为局部变量的生命周期原因. class Outer{    private int a;    public class Inner{        private int

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

在接触到开源项目 Masonry 后,里面的布局约束的链式写法让我颇感兴趣,就像下面这样: 1 2 3 4 5 6 7 8 UIEdgeInsets padding = UIEdgeInsetsMake(10, 10, 10, 10); [view1 mas_makeConstraints:^(MASConstraintMaker *make) {     make.top.equalTo(superview.mas_top).with.offset(padding.top); //with i

JavaSE8基础 链式编程 调用方法返回对象再调方法 简单示例

os :windows7 x64    jdk:jdk-8u131-windows-x64    ide:Eclipse Oxygen Release (4.7.0)        代码: class Person { public void sayHello() { System.out.println("hello world"); } } class Tools { public static Person getPersonObj() { return new Person()

C++中的链式操作

代码编译环境:Windows7 32bits+VS2012. 1.什么是链式操作 链式操作是利用运算符进行的连续运算(操作).它的特点是在一条语句中出现两个或者两个以上相同的操作符,如连续的赋值操作.连续的输入操作.连续的输出操作.连续的相加操作等都是链式操作的样例. 链式操一定涉及到结合律的问题.比如链式操作赋值操作满足右结合律,即a=b=c被解释成a=(b=c).而链式输出操作原则满足左结合律,即cout<<a<<b被解释成(cout<<a)<<b,基本

JAVA中实现链式操作(方法链)的简单例子

使用链式编程带来的简单 student package jetty; import java.util.stream.IntStream; /** * @Auther: Xiao Yu * @Date: Created in 14:52 2018/3/22 */ public class Student { private Integer id; private Integer age; private String name; private String address; private S

通过JavaScript中的链式方法实现JQuery的链式调用

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>实现JQuery的链式调用</title> </head> <body> <script> function A(){} A.prototype.v = 2; A.prototype.set = function(num)

express4.x中的链式路由句柄

1 var express = require("express"); 2 var router = express(); 3 4 router.get('/', function (req, res) { 5 res.render('articles', {titles: '文章页', content: '这是文章页的内容,method==' + req.method}); 6 }) 7 .post('/', function (req, res) { 8 res.json({msg