具有有限离散值的Ruby类

时间:2014-07-16 02:21:19

标签: ruby initialization

让我们说我打算写一个赛马投注应用程序,我想要一个可以有四个离散值的RaceResult类:WinPlace,{ {1}}和" null对象"班Show

我从C#背景来到Ruby,我通常会使用Lose,或者私有构造函数创建一系列静态只读字段,如下所示:

enum

如果课程太复杂,我会重构使用策略模式。

解决此要求的Ruby方法有哪些?我可以创建一个只能有四个实例的类吗?我在填写Google查询时遇到问题,无法找到我正在寻找的信息。

编辑:在第一个答案中,我已经找到了一些很好的方法来处理我只想要一个命名的原始值的情况。但是,如果我有兴趣扩展其行为,我需要一个自定义类。有没有办法可以修改使用类的常量方法?

2 个答案:

答案 0 :(得分:2)

不确定我是否理解你的要求,但Hash如何更像红宝石?

race_results = { win: 1, place: 2, show: 3, lose: 4 }

答案 1 :(得分:1)

根据this StackOverflow answer,在搜索" Ruby等效的枚举"时,您可以使用模块和常量构建类似枚举的结构:

module RaceResult
    LOSE = 0
    WIN = 1
    PLACE = 2
    SHOW = 4
end

result = RaceResult::WIN

这具有能够在值(例如RaceResult::WIN & RaceResult::SHOW)上使用按位运算符的额外点,即使在此特定应用程序中可能没有必要。

编辑:您甚至可以进一步为代码定义枚举功能:

def Enum(values)
    result = Module.new
    i = 0
    values.each do |name|
        result.const_set name, 2**i
        i += 1
    end
    return result.freeze
end

RaceResults = Enum ["LOSE", "WIN", "PLACE", "SHOW"]

*虽然使用这个最小的实现,但LOSE不是默认的零值/空对象。

实际C#-like enums

如编辑中所述,您还需要一些行为(函数),因此您可能希望实际使用类。我将第一个代码段(使用手动定义的模块)与this answer混合在一起,因此我们仍然可以使用通常的按位运算符,就像普通的枚举一样。在下面的代码片段中,第一个类定义创建了一个通用的Enum类,它应该由任何真实的枚举继承(这是枚举的实现)。第二类是实际的枚举,在我们的例子中是RaceResults。请注意,它继承Enum,并使用构造函数定义其常量(稍后将详细介绍)。它还定义了一个可以在其上调用的方法,仅作为示例。

class Enum
    def initialize(n)
        @value = n
    end

    def method_missing(name, *args, &blk)
        ret = @value.send(name, *args, &blk)
        ret.is_a? Numeric ? Enum.new(ret) : ret
    end
end

class RaceResults < Enum
    LOSE = self.new 0
    WIN = self.new 1
    PLACE = self.new 2
    SHOW = self.new 4

    def doSomething
        puts "did something useful, and btw, numerically I am #{@value}"
    end
end

RaceResults::WIN.doSomething

在最后一行中,您可以看到如何使用定义的方法,以及如何访问常量值。

为什么要使用构造函数来定义可能的值,您可能会问?好吧,主要是因为您仍然可以使用按位运算符(&|等),同时能够从相同的值调用任何实例方法。它比使用转换方法更透明,比实际实现运算符更懒惰。