[关闭]
@smilence 2020-02-28T02:22:46.000000Z 字数 2781 阅读 696

Chapter 4a: Class

Ruby SDE-Foundations


为什么要用Class

Data Integrity 数据完整性

对数据有很强的约束性。比如一个payment,
1. senderId receiverId amount currency必须创建的时候以参数形式传进来,而Id一定是intialize内部来自己生成,之后也只能读取,不能修改.
2. senderId receiverId这些payment创建之后,之后就不能update。
3. status不能直接修改,必须通过refund,cancel这样的函数来负责做一些别的处理后再修改。

class PasswordencryptedPassword属性永远不需要读取。

Reusability 可重用性

比如USTransfer,GBTransfer, CommercePayment这些class都share class Payment的属性和功能,那需要把前者标注为继承后者即可

分类清晰

所有关于String的函数都可以在String这个class下找到,而不用担心到底叫string_push_element还是push_element_to_string,也不用去关心哪个文件里会有。

Class Method vs Instance Method

简单地说,Instance method is associated with one "instance", 也就是单个object, 用于与这个instance直接相关的操作,比如拿这个object的attribute,更改这个object的attribute。而Class method则更像是global的函数,跟任何一个单一的instance都无关,放在这个class下面只是代表这个函数的功能和这个类别有关。Class method永远不会碰instance variable.

但到底什么时候我们要用class method呢?

1. 属于这个类别的工具包

1.1

先举一个简单的例子,如果我们想写一个函数,拿所有的Sticker,我们应该怎么写呢?
1. 我们可以用一个get_all_stickers()的global函数,不属于任何class,但这样不好,因为乱七八糟的函数都堆在一起,缺乏分类,别人很难找到这个函数
2. 我们可以写在class Sticker下面作为一个instance method, 但这样就意味着我们想拿所有的sticker,还要去找一个图片来新建一个sticker,然后通过这个没用的effect来做 effect.getAllStickers(), 完全不合常理。
3. 我们可以在class Sticker下面写一个class method, 这样我们就可以有Sticker.getAllSticker() (实际做的事情就是去数据库里把所有的sticker object拿出来),既合乎常理,又让人很方便的在Sticker这个类别下面找到这个有用的功能

1.2 Create Object

另一个例子是我们想有很多种create object的方法,只有一个基本的initialize不够用。

首先initialize本身就可以认为是一个class method,因为还没有任何一个object的时候,就可以用Cart.new()了. (如果所有的都是instance method的话只能用于instance的话,那第一个instance又是哪里来的?)

那比如我们想在Cart下面写一个createFromWishList这个函数,把wishlist里面的东西copy到新的cart里。如果不借助class method,那么我们必须每次都这么写

  1. items = wishlist.items # 想象一下如果这段逻辑远比这一行复杂,是50行代码
  2. userid = wishlist.userid
  3. c = Cart.new(items, userid)

相比于用class method

  1. class Cart
  2. def self.createFromWishList(list)
  3. items = wishlist.items
  4. userid = wishlist.userid
  5. return Cart.new(items, userid)
  6. end
  7. end
  8. # 定义好以上的内容,以后每次只要写下面一行就行了
  9. c = Cart.createFromWishList(wishlist)

2. 代表这个类别共有的属性

以购物车这个class为例

  1. class Cart
  2. def initialize(userid, items=[])
  3. @items = items # hash
  4. @coupon = nil
  5. @userID = userid
  6. end
  7. # 这属于整个类别共享的属性,跟哪个object无关(不依赖于`@items`, `@coupon`, `@userID`)
  8. def self.maxItemAmount()
  9. # obtain location (from ip / GPS) and get max item limit
  10. return current_location() == 'US' ? get_us_item_limit() : get_global_item_limit()
  11. end
  12. def addItems(item, amount = 1)
  13. # 其他想用maxAmount的人不用了解maxAmount是怎么计算出来的,就当是黑盒子
  14. raise error if items.values.sum + amount > Cart.maxItemAmount
  15. @items[item.id] += amount
  16. end
  17. end
  18. class RecommendList
  19. # ...
  20. def initialize(userid)
  21. max_amount = Cart.maxItemAmount
  22. # 确保接下来推荐的列表小于等于购物车最大容量
  23. end
  24. end

当然,如果maxItemAmount是固定值,我们也可以把MAX_ITEM_AMOUNT = 50这样一个CLASS_CONSTANT属于class的常数放在class下面。但在不是常数的情况下,那么就需要有class method来代表这个属于Cart这个类别共有的事情。

另一个例子,是我们用class variable来记录属于这个类别共有的一个属性

  1. class Cart
  2. @@totalCarts = 0
  3. def initialize(userid, items={})
  4. @items = items # hash
  5. @coupon = nil
  6. @userID = userid
  7. @@totalCarts += 1
  8. end
  9. def self.totalCarts()
  10. @@totalCarts
  11. end
  12. end
  13. item1 = Item.new(100)
  14. item2 = Item.new(200)
  15. c1 = Cart.new(1, {item1 => 2})
  16. c2 = Cart.new(2, {item2 => 3})
  17. p Cart.totalCarts # => 2
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注