[关闭]
@smilence 2020-02-28T10:23:09.000000Z 字数 2438 阅读 831

Chapter 4b: Class (Advanced)

Ruby SDE-Foundations


以下内容仅供参考阅读

Class Method vs Instance Method

3. 效率的差别*

Instance method必须要新建instance, 必须每次新建一个instance = Class.new(), 需要在内存当中存储这个instance的variable 以及 method的代码。有多少个instance就有多少这些东西。

有一类class可以被认为是一个globally共享的toolbox,大家都可以用,没有必要每次都新建一个,逻辑对每个人都是一样的,那么内存中只需要存一开始的那段代码即可。

还是那个例子,我们想拿所有的Sticker, 我们一定要用instance method的话,我们也可以去class Sticker以外新建一个类,专门负责这件事情:

  1. class StickerInventory
  2. def initialize()
  3. end
  4. def getAllStickers()
  5. ...
  6. end
  7. end
  8. inventory_for_april = StickerInventory.new() #内存里增加了一个object
  9. april_stickers = inventory_for_april.getAllStickers
  10. ...
  11. # 可能在下一层函数里
  12. inventory_for_james = StickerInventory.new() #内存里又增加了一个object
  13. james_stickers = inventory_for_james.getAllStickers
  14. # 当然你可以用inventory = StickerInventory.new() 然后一直用同一个,但是需要传来传去会很麻烦
  15. ...

相比之下,

  1. class Sticker
  2. self.getAllStickers(userid)
  3. ...
  4. end
  5. end
  6. # 每次都用内存中存储的同样一段代码
  7. inventory_for_april = Sticker.getAllStickers()
  8. inventory_for_james = Sticker.getAllStickers()

所以前者不仅要多写了一个class,而且运行效率还更低。

4. 进阶应用*

4.1 Factory method

  1. # 创建一个class负责统一create payment,因为用户输入的时候不会自己选择是新建哪种
  2. class PaymentFactory
  3. def self.createPayment(senderId, receiverId, currency, amount, item = nil)
  4. if item != nil
  5. return CommercePayment.new(senderId, receiverId, currency, amount, item)
  6. elseif currency == 'USD'
  7. return USTransfer.new(senderId, receiverId, amount)
  8. elseif currency == 'GBP'
  9. return GBTransfer.new(senderId, receiverId, amount)
  10. else
  11. raise Error("Not supported")
  12. end
  13. end
  14. end
  15. # 写好这些之后,别人就不需要关心你内部是怎么分类实现的,只要用`PaymentFactory.createPayment`就是万能的

4.2 Cache

  1. # 创建一个class作为缓存专门负责存下已经拿取过的payment,比如从payment history一个个点进payment receipt。
  2. # 这样取过的就不需要每次都去database取。这个cache是global的。
  3. class PaymentCache
  4. @@cache = nil
  5. def initialize(payments = {})
  6. @payments = payments
  7. end
  8. # 无论哪里需要这个cache,都应该去拿同一个cache object
  9. def self.get()
  10. # 如果还没有建过的话,就新建一个cache object
  11. if @@cache == nil
  12. return self.new()
  13. else
  14. return @@cache
  15. end
  16. end
  17. def self.getPayment(id)
  18. cache = self.get()
  19. if cache.has_key?(id)
  20. return cache[id]
  21. else
  22. payment = get_payment_from_database(id)
  23. cache[id] = payment_obj
  24. return payment
  25. end
  26. end
  27. end
  28. # 用这个class的人不需要担心自己去新建PaymentCache 然后传来传去
  29. p1 = PaymentCache.getPayment(1) # 去database拿了放进cache
  30. p2 = PaymentCache.getPayment(2) # 去database拿了放进cache
  31. ....
  32. # 下次再想拿1对应的payment
  33. p1 = PaymentCache.getPayment(1) # 从cache里而不是database拿出来,因为已经有1这个key了

如果每次都新建一个cache, 那么每次都是空的,不会有之前的数据。如果第一次建了之后就到处传,则显得非常乱,给每一层函数都增加了一个参数。更不用说下层函数无法给上层传。我们希望用class variable去document一个唯一的instance,是所有人所共享的。

当然,我们可以只用class method和class variable,连这个唯一的instance都不需要,我们可以只用一个@@payments作为class variable。但那样在实际运用时候的缺点在于,如果我们需要多个继承PaymentCache的class,我们又不希望他们把东西都放在一起,那么我们就需要每个class对应一个object。否则的话,所有的child class都会用同一个@@payments来保存。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注