Reputation: 404
I have a project involving a webshop for different kinds of products. From what I understand, if you have multiple classes that inherit from one base class, the factory design pattern is the way to go. I only have trouble deciding where to put the logic for actually deciding which factory to use.
I have created classes and factory classes for the different kinds of products like so.
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;
}
}
Now when an order is completed an event is triggered.
public void OrderCompleted(int orderId, List<int> productIds);
So here I have a list of int's from which I want to make product object so I can call the
CompleteOrder
function on each of them. The problem is to know the type of the product I need to get the product type from the database which is filled in the populate function.
What I could do is create a function public ProductFactory GetFactory(int id)
in the ProductFactory. But then the factory is can not be an abstract class.
Another option would be creating a function public static Product GetProduct(int id)
in the product class. Which then first figures out which factory to use and the returns the created product.
But both of this options feel weird. Am I missing something? Or is one of these the actual way to go?
Cheers.
Upvotes: 3
Views: 793
Reputation: 46947
So skip the Populate
function in the Product class. That is the duties of the factory to do. And I would go with one factory class to create all types of products. (The factory can if needed call other classes to help create the product)
Something like:
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);
...
}
}
Upvotes: 2
Reputation: 418
look at this example of factory method design pattern: http://jayeshtanna.azurewebsites.net/2018/11/25/factory-method-design-pattern/
Upvotes: 0
Reputation: 718
Eh, just don't over think it. Design patterns should be tools you wield to create your code, if I read your question correctly, I think you are more in a state of the design pattern wielding you.
So unless the pattern helps you, do not over complicate your code with it.
That said, If you do choose to go for a pattern, your situation seems simple enough to go for Magnus's solution.
Upvotes: 0