@smilence
2020-02-28T10:22:46.000000Z
字数 2781
阅读 835
Ruby
SDE-Foundations
对数据有很强的约束性。比如一个payment,
1. senderId
receiverId
amount
currency
必须创建的时候以参数形式传进来,而Id
一定是intialize
内部来自己生成,之后也只能读取,不能修改.
2. senderId
receiverId
这些payment创建之后,之后就不能update。
3. status
不能直接修改,必须通过refund
,cancel
这样的函数来负责做一些别的处理后再修改。
class Password
的encryptedPassword
属性永远不需要读取。
比如USTransfer
,GBTransfer
, CommercePayment
这些class都share class Payment
的属性和功能,那需要把前者标注为继承后者即可
所有关于String
的函数都可以在String
这个class下找到,而不用担心到底叫string_push_element
还是push_element_to_string
,也不用去关心哪个文件里会有。
简单地说,Instance method is associated with one "instance", 也就是单个object, 用于与这个instance直接相关的操作,比如拿这个object的attribute,更改这个object的attribute。而Class method则更像是global的函数,跟任何一个单一的instance都无关,放在这个class下面只是代表这个函数的功能和这个类别有关。Class method永远不会碰instance variable.
但到底什么时候我们要用class method呢?
先举一个简单的例子,如果我们想写一个函数,拿所有的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这个类别下面找到这个有用的功能
另一个例子是我们想有很多种create object的方法,只有一个基本的initialize
不够用。
首先initialize
本身就可以认为是一个class method,因为还没有任何一个object的时候,就可以用Cart.new()
了. (如果所有的都是instance method的话只能用于instance的话,那第一个instance又是哪里来的?)
那比如我们想在Cart
下面写一个createFromWishList
这个函数,把wishlist里面的东西copy到新的cart里。如果不借助class method,那么我们必须每次都这么写
items = wishlist.items # 想象一下如果这段逻辑远比这一行复杂,是50行代码
userid = wishlist.userid
c = Cart.new(items, userid)
相比于用class method
class Cart
def self.createFromWishList(list)
items = wishlist.items
userid = wishlist.userid
return Cart.new(items, userid)
end
end
# 定义好以上的内容,以后每次只要写下面一行就行了
c = Cart.createFromWishList(wishlist)
以购物车这个class为例
class Cart
def initialize(userid, items=[])
@items = items # hash
@coupon = nil
@userID = userid
end
# 这属于整个类别共享的属性,跟哪个object无关(不依赖于`@items`, `@coupon`, `@userID`)
def self.maxItemAmount()
# obtain location (from ip / GPS) and get max item limit
return current_location() == 'US' ? get_us_item_limit() : get_global_item_limit()
end
def addItems(item, amount = 1)
# 其他想用maxAmount的人不用了解maxAmount是怎么计算出来的,就当是黑盒子
raise error if items.values.sum + amount > Cart.maxItemAmount
@items[item.id] += amount
end
end
class RecommendList
# ...
def initialize(userid)
max_amount = Cart.maxItemAmount
# 确保接下来推荐的列表小于等于购物车最大容量
end
end
当然,如果maxItemAmount
是固定值,我们也可以把MAX_ITEM_AMOUNT = 50
这样一个CLASS_CONSTANT
属于class的常数放在class下面。但在不是常数的情况下,那么就需要有class method来代表这个属于Cart这个类别共有的事情。
另一个例子,是我们用class variable来记录属于这个类别共有的一个属性
class Cart
@@totalCarts = 0
def initialize(userid, items={})
@items = items # hash
@coupon = nil
@userID = userid
@@totalCarts += 1
end
def self.totalCarts()
@@totalCarts
end
end
item1 = Item.new(100)
item2 = Item.new(200)
c1 = Cart.new(1, {item1 => 2})
c2 = Cart.new(2, {item2 => 3})
p Cart.totalCarts # => 2