【问题标题】:Factory method and where to choose which factory is to be used工厂方法以及在哪里选择要使用哪个工厂
【发布时间】:2020-04-20 15:03:51
【问题描述】:

我有一个项目,涉及不同种类产品的网上商店。据我了解,如果您有多个从一个基类继承的类,那么工厂设计模式就是要走的路。我只是很难决定将实际决定使用哪个工厂的逻辑放在哪里。

我已经为不同种类的产品创建了类和工厂类。

public class Product
{
    public int ID { get; protected set; }
    public string Name { get; set; }
    public ProductType Type { get; private set; }

    public Product(int id)
    {
        ID = id;
        Populate();
    }

    public virtual void CompleteOrder()
    {
        //SendMailToSupplier();
    }

    private void Populate() 
    {
        //database stuff including setting the type
    }
}

public class DigitalProduct : Product
{
    public DigitalAsset ProductAsset { get; private set; }

    public DigitalProduct(int id, DigitalAsset asset) : base(id)
    {
        ProductAsset = asset;
    }

    public override void CompleteOrder()
    {
        base.CompleteOrder();
        //SendAssetToUser();
    }
}

public class PrintProduct : Product
{
    public PrintInformation Information { get; private set; }

    public PrintProduct(int id, PrintInformation information) : base(id)
    {
        Information = information;
    }

    public override void CompleteOrder()
    {
        base.CompleteOrder();
        //PreparePrintingFlle();
    }
}

public abstract class ProductFactory
{
    public abstract Product CreateProduct(int id);
}

public class GenericProductFactory : ProductFactory
{
    public override Product CreateProduct(int id)
    {
        return new Product(id);
    }
}

public class DigitalProductFactory : ProductFactory
{
    public override Product CreateProduct(int id)
    {
        DigitalAsset asset = GetDigitalAsset(id);
        return new DigitalProduct(id, asset);
    }   

    private DigitalAsset GetDigitalAsset(int id)
    {
        DigitalAsset asset = new DigitalAsset();
        //IO stuff
        return asset;
    }
}

public class PrintProductProductFactory : ProductFactory
{
    public override Product CreateProduct(int id)
    {
        PrintInformation information = GetPrintInformation(id);
        return new PrintProduct(id,information);
    }

    private PrintInformation GetPrintInformation(int id)
    {
        PrintInformation information = new PrintInformation();
        //database stuff
        return information;
    }
}

现在,当订单完成时,会触发一个事件。

public void OrderCompleted(int orderId, List<int> productIds);

所以在这里我有一个 int 列表,我想从中制作产品对象,这样我就可以调用 CompleteOrder 对它们每个都有作用。问题是要知道我需要从填充函数中填写的数据库中获取产品类型的产品类型。

我能做的是在 ProductFactory 中创建一个函数 public ProductFactory GetFactory(int id)。但是工厂不能是抽象类。

另一种选择是在产品类中创建一个函数public static Product GetProduct(int id)。然后首先确定使用哪个工厂并返回创建的产品。

但这两个选项都感觉很奇怪。我错过了什么吗?还是其中一种是实际可行的方法?

干杯。

【问题讨论】:

  • 基类不应该知道它的派生类;这将违反开闭原则。将Populate 中的逻辑放入您的工厂。
  • 除了马格努斯的回答,我还要补充一点,感觉就像你错过了另一个分裂。如果一个订单可以由多个产品组成,那么一个产品可以完成一个订单是不对的。订单应该由可能的 OrderId、CustomerId、产品列表等组成。应该具有 CompleteOrder 功能。
  • @sr28 你是对的。这里的问题是我们正在使用第 3 方包,它只支持通过事件扩展他们的软件调用。所以我无法控制那部分

标签: c# factory-pattern abstract-factory


【解决方案1】:

所以跳过 Product 类中的Populate 函数。这是工厂的职责。我会选择一个工厂类来创建所有类型的产品。 (工厂可以根据需要调用其他类来帮助创建产品)

类似:

public class ProductFactory
{
     public Product GetProductById(int id)
     {
          var dbProduct = FetchFromDb(id);
          switch(dbProduct.Type)
          {
              case "Print"
                 return CreatePrintProduct(dbProduct);
              case "Digital"
                 return CreateDigitalProduct(dbProduct);
          }
     }


     private DigitalProduct CreateDigitalProduct(DbEntity dbProduct)
     {
         var product = new DigitalProduct(dbProduct.Id);
         //Initialize the product

         return product;
     }

     //You might also want a batch function to avoid calling the database for each product.
     public IEnumerable<Product> GetProductByIds(IEnumerable<int> ids)
     {
          var dbProducts = FetchFromDb(ids);
          ...
     }
}

【讨论】:

  • 感谢您的回答和示例。一个问题。在这种情况下,工厂返回多个可能的类之一。我认为工厂总是返回一个特定的类(即用于打印的 PrintProductFactory 和用于数字的单独的 DigitalProductFactory)。这只是一种误解吗?
  • 没有工厂返回所有产品通用的基类或接口,但实际对象是派生类型。
【解决方案2】:

呃,别想太多了。设计模式应该是您用来创建代码的工具,如果我正确阅读了您的问题,我认为您更处于使用您的设计模式的状态。

因此,除非该模式对您有帮助,否则不要使用它使您的代码过于复杂。

也就是说,如果您确实选择了一种模式,那么您的情况似乎很简单,可以采用 Magnus 的解决方案。

【讨论】:

    【解决方案3】:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-14
      • 2011-01-05
      • 1970-01-01
      相关资源
      最近更新 更多