如何设计自定义产品构建器

时间:2014-10-23 09:17:19

标签: asp.net database-design e-commerce

我正在开发一个应用程序,用于生成汽车等产品的估算值。 因此,当选择汽车制造模型时,我需要向用户提供各种选项(选项可能在不同的组中,如车轮,座椅装饰,行李箱配件)

根据群组的不同,客户可以选择该群组中的一个或多个选项;如果选择某个选项 - 其他一些选项可能会被禁用;并非所有选项都适用于每个制作模型 那么,有几个规则需要为不同的组定义,以指示允许哪些组合和不允许的组合?

我应该如何为此设计数据库,并且在开发此应用程序时是否有可以利用的模式?

1 个答案:

答案 0 :(得分:0)

我用以下结构解决了类似的要求,并在上面的条款中重写:

  1. 零件
  2. 汽车
  3. 以下注释:

    1. 零件本身是独立的,每个零件都有一个零件号。
    2. 汽车模板本身就是独立的。
    3. 可以将零件添加到选项组,并且许多选项组属于汽车。
    4. 如果没有汽车,则选项组不能存在。
    5. 一个群组可以依赖另一个群体
    6. 我需要防止循环引用
    7. 在我编写类代码(测试驱动开发)之前,我开始使用我的模型来编写测试用例,它给了我代码(在C#中):

      var dieselEngine = new Sku("diesel 2_litre,",1000);
      var petrolEngine2 = new Sku("petrol_2_litre",800);
      var petrolEngine25 = new Sku("petrol_25_litre",900);
      
      var petrolTurbo = new Sku("petrol_turbo",2000);
      var dieselTurbo = new Sku("diesel_turbo",2000);
      
      var car = new Car("myCar");
      
      car.AddGroup("Engines");
      car.AddSkuToGroup("Engines", diselEngine);
      car.AddSkuToGroup("Engines", petrolEngine2);
      car.AddSkuToGroup("Engines", petrolEngine25);
      
      car.AddGroup("Turbos");
      car.AddSkuToGroup("Turbos", petrolTurbo);
      car.AddSkuToGroup("Turbos", dieselTurbo);
      
      car.SetRequirement(diselEngine, dieselTurbo);
      car.SetRequirement(petrolTurbo, petrolEngine2);
      car.SetRequirement(petrolTurbo, petrolEngine25);
      

      我在组上添加依赖选项,而不是在Sku上,因为一个部件可能存在于多个汽车中,但可能对每个特定汽车具有不同的依赖关系。

      我必须通过root car对象放置所有内容,这将检查并强制执行我的所有业务规则(例如检查和防止循环引用)。

      如果通过汽车对象的所有访问都感觉笨拙,您可以始终让car.AddGroup函数返回一个组以使代码更有意义阅读:

      var engines = car.AddGroup("Engines");
      engines.AddSkuToGroup(diselEngine);
      engines.AddSkuToGroup(petrolEngine2);
      engines.AddSkuToGroup(petrolEngine25);
      

      但不要忘记,商业规则只能由汽车强制执行,因为汽车可以看到所有组件。所以我们总是通过root链接:

      class ConfigurableProduct
      {
          List<Group> groups = new List<Group>();
          Group NewGroup(string name)
          {
              var group = new Group(this, name);
              this.groups.Add(group);
              return group;
          }
      
          bool ContainsSku(string skuId)
          {
              foreach (var group in this.Groups)
              {
                  if (group.ContainsSku(skuId))
                      return true;
              }
              return false;
          }
      }
      
      class Group
      {
          Group(ConfigurableProduct parent, string name)
          {
              this.parent = parent;
              this.name = name;
          }
      
          string name;
          List<string> skuIds = new List<string>();
      
          ConfigurableProduct parent;
      
          void AddSkuToGroup(string skuId)
          {
              // enforce invariants via parent, call functions as reuqired
              if (this.parent.containsSku(skuId))
                  throw new Exception("SKU already exists in this configurable template, cannot exist twice");
              // do other things, like check circular references etc, all via this.parent
      
          }
      
          bool ContainsSku(string toFind)
          {
              foreach (var skuId in this.skuIds)
              {
                  if (skuId == toFind)
                      return true;
              }
              return false;
          }
      }
      

      对于实际的数据库存储我最后会担心持久性,它可能是文本文件,MSSQL数据库,MySQL数据库,MongoDB,有很多选项。

      我发现专注于我想在我的应用程序中使用代码的方式总是有用的,而不是数据库需要如何使用的具体细节,因为存储可以通过返回类的存储库接口进行抽象(a普通的旧POCO类,但在这种情况下,我们已经开始充实业务逻辑以防止无效状态。)

      对于前端,您可能希望通过JSON向下推送所有可以动态显示选项的角度或敲除,并根据组之间的依赖关系显示或隐藏不同的元素。

      工作前端示例

      我不确定您使用的前端绑定(或者如果您只使用剃刀,在这种情况下,您需要在服务器上存储状态并刷新每个选择),但我提供了一个使用Knockoutjs的示例这里:http://jsfiddle.net/g18c/5jt9bwsv/1/具有工作依赖项和动态javascript对象构建器。

      1. 按组
      2. 循环提供的JSON产品
      3. 创建根据目标依赖关系更改的计算字段
      4. 通过淘汰赛绑定视图
      5. 然后可以简单地将选定的SKU传递给服务器,任何业务规则也可以在前端javascript中实现。

        当然,从客户端发送到服务器的任何数据都需要通过在服务器上构建产品图并检查提供的SKU是否有效来验证(即您不希望允许使用柴油涡轮增压器)被选为汽油发动机。)