SKU选择控件的实现


###一.知识准备
在淘宝网,产品指的是标准化产品,由(类目,关键属性)决定,如一个手机产品由 (手机类目,(品牌,型号))决定。 SPU,Standard Product Unit(标准化产品单元),一般是由(关键属性:属性值)这样的键值对组成的。 SKU,Stock Keeping Uint(库存量单位),由(销售属性:属性值)的键值对,它直接影响买家的购买和卖家的库存管理,如 某个服装的 (颜色:黑色,尺码:XXL)。
总结一下就是SPU是标准化产品单元,区分品种;SKU是库存量单位,区分单品;商品特指与商家有关的商品,可对应多个SKU。我们通常所说的”宝贝”其实指的是商品。当在购买存在多个SKU的宝贝的时候,我们第一步需要做的就是选择一个SKU,然后才能进行购买加入购物车等操作。

二.接口数据和算法分析

为了便于计算机实现,产品的关键属性以及销售属性以及他们的属性值在计算机系统都会进行编码,使用数字来表示,方便计算机进行计算。如果想详细了解淘宝某个类目下的某类产品的各种属性可以通过属性工具进行查看: 属性工具
这里以淘宝开放平台的SKU结构为例子讲解SKU对象
一个SKU结构 一般包含:

  • skuId
  • SKU的组成(p1:v1;p2:v2;p3:v3…),用来表示当前SKU由哪些销售属性组成以及对应的属性值是什么
  • 还有当前SKU键值对对应的中文名字符串(因为上面的组成都是编号)
  • 当前SKU的库存
  • 当前SKU的价格

当然不同的接口返回的SKU的数据结构会不太相同,但是包含的信息量是一致的。

以下是网页中商品(宝贝的数字id为13890058021)的SKU选择控件的显示,从中可以看出一些东西

  • 一个属性 一般对应多个属性值,用户需要对属性值进行选择
  • 当有多个属性存在时,用户需要进行多维度的选择,最终的SKU是各种销售属性键值对组合而成
  • 当一个属性的属性值被选择之后可能会对其他的属性的属性值的可选性产生影响,因为某些SKU可能没有库存了。这样一个SKU属性值选择了之后,别的属性的属性值选择按钮就会被disabled了.

以上例子的数据TOP接口的数据返回为:

{
  "item_get_response": {
    "item": {
    ...
      "property_alias": "1627207:3232483:格子裙(七分袖,模特版);1627207:3232484:格子裙(九分袖,袖口无分叉)",
      ...
      "skus": {
        "sku": [
          {
            "created": "2012-08-31 19:18:51",
            "modified": "2012-09-20 10:46:41",
            "price": "140.00",
            "properties": "1627207:3232484;20509:28314",
            "properties_name": "1627207:3232484:颜色分类:天蓝色;20509:28314:尺码:S",
            "quantity": 0,
            "sku_id": 24659375069
          },
          {
            "created": "2012-08-31 19:18:51",
            "modified": "2012-09-08 21:49:39",
            "price": "140.00",
            "properties": "1627207:3232484;20509:28315",
            "properties_name": "1627207:3232484:颜色分类:天蓝色;20509:28315:尺码:M",
            "quantity": 0,
            "sku_id": 24659375070
          },
          {
            "created": "2012-08-31 19:18:51",
            "modified": "2012-09-21 10:40:03",
            "price": "140.00",
            "properties": "1627207:3232484;20509:28316",
            "properties_name": "1627207:3232484:颜色分类:天蓝色;20509:28316:尺码:L",
            "quantity": 0,
            "sku_id": 24659375071
          },
          {
            "created": "2012-08-31 19:18:51",
            "modified": "2012-09-22 20:40:48",
            "price": "140.00",
            "properties": "1627207:3232484;20509:28317",
            "properties_name": "1627207:3232484:颜色分类:天蓝色;20509:28317:尺码:XL",
            "quantity": 5,
            "sku_id": 24659375072
          },
          {
            "created": "2012-09-08 21:49:39",
            "modified": "2012-09-21 18:54:08",
            "price": "140.00",
            "properties": "1627207:3232483;20509:28314",
            "properties_name": "1627207:3232483:颜色分类:军绿色;20509:28314:尺码:S",
            "quantity": 44,
            "sku_id": 24901123154
          },
          {
            "created": "2012-09-08 21:49:39",
            "modified": "2012-09-22 21:11:18",
            "price": "140.00",
            "properties": "1627207:3232483;20509:28315",
            "properties_name": "1627207:3232483:颜色分类:军绿色;20509:28315:尺码:M",
            "quantity": 45,
            "sku_id": 24901123155
          },
          {
            "created": "2012-09-08 21:49:39",
            "modified": "2012-09-22 15:52:56",
            "price": "140.00",
            "properties": "1627207:3232483;20509:28316",
            "properties_name": "1627207:3232483:颜色分类:军绿色;20509:28316:尺码:L",
            "quantity": 39,
            "sku_id": 24901123156
          },
          {
            "created": "2012-09-08 21:49:39",
            "modified": "2012-09-16 12:03:18",
            "price": "140.00",
            "properties": "1627207:3232483;20509:28317",
            "properties_name": "1627207:3232483:颜色分类:军绿色;20509:28317:尺码:XL",
            "quantity": 50,
            "sku_id": 24901123157
          }
        ]
      },
      ...
    }
  }
}

上面销售属性有两个: 颜色分类(编号1627207)的属性值有两种 军绿色(别名 格子裙(七分袖,模特版) 编号3232483) 天蓝色(别名 格子裙(九分袖,袖口无分叉) 编号3232484)
尺码(编号20509)的属性值有四种 S(编号28314) M(编号28315) L(编号28316) XL(编号28317)

返回的所有的sku中只有那些库存量大于0的sku才是有效sku,一般情况sku属性个数不会超过3个。

初始状态是所有的属性值都处于非选中状态,如果此时你选择尺码S,那么程序需要对还没有选择的属性的属性值进行检测,也就是对颜色分类的每一个属性值进行检测,以判断在此情况下其是否可以被选择,如果不能被选择,则需要被设置为禁用状态,首先对 格子裙(七分袖,模特版) 编号3232483进行检验 查看 1627207:3232483;20509:28314(sku中各个属性的先后次序是一定的)是否能够存在,到所有的sku中查看发现此组合是可以存在的且为一个完整的sku. 接着来检查 格子裙(九分袖,袖口无分叉)编号3232484 , 也就是检查1627207:3232484;20509:28314组合是否能够存在 发现其匹配的sku库存为0,则需要将其设置为不可选,所以便有了上图的情形。

上面的分析毕竟为人类大脑思考的模式,当需要用计算机来实现的时候,需要进行再抽象,找出算法。 如果某个属性值被选中了,可以看作某个属性键值对被选中了。假设某个宝贝的一个存货大于0的sku为 abc (其中a,b,c都是键值对,将其看作一个集合集合中有三个元素a,b,c),那么通过这个sku可以知道sku属性的可选组合包括 a,ab,ac,b,bc,c,abc,所以本质是求此sku的非空子集。如果存在多个库存大于0的sku,则需要分别求其非空子集,最后得到的所有的集合(有些集合可能重复了需要剔除)就是所有sku属性可选组合了,可以用来检验属性值的可选性.

计算组合的非空子集的算法可以使用二进制位的方式进行计算。 对构成一个SKU的属性键值对的组合而言,在其某一个子集中,每一个属性键值对的状态无非有两个,不存在和存在,我们分别用0和1表示,那么有n个键值对的SKU所有的子集个数为2^n 去除一个空集后为2^n - 1.

c   b   a   
0   0   1      a 
0   1   0      b
0   1   1      ab
1   0   0      c
1   0   1      ac
1   1   0      bc
1   1   1      abc

从上面的枚举可以看到,算abc的非空子集只需index 从1到2^n - 1 进行遍历,每次将index的二进制位中为1的对应位置的字母选中组成一个集合.最后得到所有可能存在的属性键值对组合的集合。 检测的方法就是对非选中属性的每一个属性值进行检测,将其键值对和已经选择了的键值对组成一个集合然后判断这个集合是不是存在于上面算出的所有的集合中,如果存在则说明可选,否则不可选。

三.功能实现

控件实现的重点就是,某个属性值按钮选择后其他属性的属性值按钮的可选择性状态的更新,以及选择了一个属性值之后,需要检查当前已经选择的”属性属性值对”组合 能否构成一个完整的SKU,如果能则将控件的selectedSku设置为指定的SKU对象以及更新显示的库存和价格,否则当前SKU设置为nil.

数据准备

在数据准备阶段,

  1. 需要建立一个SKU的Map,key为SKU的属性键值对组合 ,value为SKU对象
  2. 需要一个SKU的键值对可能存在的组合的一个Map,主要是为了检测一个属性值按钮选择之后对其他属性的属性值可选性的影响,key为键值对组合,value就为1,没有实际意义
  3. 如果在所有有存货的SKU中都没有某个属性值出现,那么需要将其剔除,要不然那个属性值按钮一直处于disabled状态

创建和状态更新

当数据都准备好了,就开始针对每一个属性创建出其所有的属性值的按钮控件,按钮显示的属性值对应的中文。 所有的属性值按钮都创建OK了之后,当我们点击某个属性值按钮之后,需要根据之前创建的”SKU的键值对可能存在的组合子集”对所有的还没有选择的属性的属性值的可选性进行更新。

dfas /
Published under (CC) BY-NC-SA in categories Programming  tagged with iOS  SKU  Taobao