0

我有一个对象PersistentObject,你可以认为它是从 ORM 中提取出来的,它是一个你可以在你的编程语言中本地使用的对象(与后端无关),它有方法loadsave用于提交对数据库的更改。

我希望我PersistentObject是有故障的,即我希望能够将它初始化为一个轻量级指针,该服务器仅引用数据库中的对象。当(如果)那一刻到来时,我可以通过实际访问数据库并获取它来将它放入内存中。这里的重点是能够将此对象作为引用添加到集合中,而无需获取该对象。我还希望能够使用经典构造函数以老式方式初始化对象,然后将其提交到数据库(当您需要从头开始创建新对象而不是操作现有对象时,这很方便)。

所以我有一个具有多个构造函数的对象:一个经典的,一个基于数据库中的对象 GUID 创建故障的一个。当对象被初始化为故障时,我希望实例方法能够以实例变量的形式访问该状态,因为故障上的操作与完全加载的对象上的操作不同。但是出于显而易见的原因,我不希望客户弄乱我的内部状态,所以我不想为 ivar 创建访问器。所以我的问题是,我如何从对象实例中的类方法初始化/设置一个 ivar,以使我的类的外部客户端不能弄乱它(即将其值设置为其他值)?

对不起所有的话,代码应该使它更清晰。我尝试了一些显然不起作用但很好地说明了这一点的方法。抱歉,如果这是一个基本问题,我对 Ruby 还是很陌生。

class PersistentObject
    def initialize(opts={})
        @id = opts[:id] || new_id
        @data = opts[:data] || nil
    end

    def self.new_fault(id)
        new_object = PersistentObject.new
        new_object.@fault = true            #<----- How do you achieve this?
        new_object
    end

    def new_id
        #returns a new globally unique id
    end

    def fault?
        @fault
    end

    def load
        if fault?
            #fault in the object from the database by fetching the record corresponding to the id
            @fault = false
        end
    end

    def save
        #save the object to the database
    end
end

#I create a new object as a fault, I can add it to collections, refer to it all I want, etc., but I can't access it's data, I just have a lightweight pointer which can be created without ever hitting the database
o = PersistentObject.new_fault("123")

#Now let's suppose I need the object's data, so I'll load it
o.load

#Now I can use the object, change it's data, etc.
p o.data
o.data = "foo"

#And when I'm ready I can save it back to the database
o.save

编辑:我应该说我并不打算从类方法访问该实例的 ivar,我很高兴听到一个惯用的 Ruby 模式来解决这个问题。

4

3 回答 3

1

You could use instance_eval:

new_object.instance_eval { @fault = true }

or instance_variable_set:

new_object.instance_variable_set(:@fault, true)
于 2013-05-28T13:02:49.580 回答
0

如果您的目标是设置实例变量,那么我同意斯蒂芬的回答。要回答您的编辑,另一种方法是向构造函数添加另一个选项:

class PersistentObject
    def initialize(opts={})
        @id = opts[:id] || new_id
        @data = opts[:data] || nil
        @fault = opts[:fault] || false
    end

    def self.new_fault(id)
        self.new(fault: true)
    end

    ...

不幸的是,Ruby 非常规的私有/受保护实现使它们无法解决这个问题。

于 2013-05-28T17:11:34.150 回答
-1

这是不可能的。而且我不是在谈论“在 Ruby 中不可能”,我是在谈论数学上、逻辑上的不可能。你有两个要求:

  1. 不应允许设置另一个对象@fault
  2. 应该允许设置另一个对象@fault。(记住,PersistentObject只是另一个对象。)

很明显,这两个要求相互矛盾,因此您想要的根本无法完成。时期。

您可以创建一个attr_writerfor @fault,然后PersistentObject可以写入它……但其他人也可以。您可以制作那个作家private,然后PersistentObject需要使用元编程(即send)来规避访问保护……但其他人也可以。您可以使用instance_variable_setto直接PersistentObject设置@fault……但其他人也可以。

于 2013-05-28T13:09:06.483 回答