Как реализовать фабричный шаблон, который динамически загружает новые продукты (принцип открытого закрытия)? - PullRequest
0 голосов
/ 20 апреля 2020

В фабричном методе мы должны написать регистр переключения или операторы if, чтобы решить, какой экземпляр создать и вернуть. Это нарушает принцип открытого закрытия, потому что - каждый раз, когда добавляется новый продукт, код фабричного метода должен обновляться.

Есть ли способ сделать эту динамику c - так, чтобы добавить новый продукт не требует каких-либо изменений заводского метода?

Например: в python мы можем импортировать пакет со списком всех доступных продуктов. Метод фабрики загружает структуру данных dict со всеми доступными продуктами вместе с их классом. Следовательно, при добавлении нового продукта код фабрики не нужно менять. Достаточно, чтобы в код пакета, который фабрика использует для импорта классов продуктов, был добавлен только продукт.

1 Ответ

0 голосов
/ 21 апреля 2020

Я не знаю, может ли это вам как-то помочь, но если вы используете конструктор без параметров в своих классах продукта, вы можете использовать этот пример. Конечно, реализация может отличаться в зависимости от ваших потребностей. Классы продуктов также могут быть определены в другой сборке.

/// <summary>
/// Product common interface.
/// </summary>
public interface IProduct
{
}
/// <summary>
/// Definition of an apple product.
/// </summary>
public class Apple : IProduct
{
    public string Gauge { get; set; }
}
/// <summary>
/// Definition of a pear product.
/// </summary>
public class Pear : IProduct
{
    public string Sweetness { get; set; }
}
/// <summary>
/// Factory class.
/// </summary>
public class ProductFactory
{
    /// <summary>
    /// List of product types found in the current assembly.
    /// </summary>
    private static IList<Type> ProductTypes = new List<Type>();
    /// <summary>
    /// Initializes the list of product types.
    /// </summary>
    public static void Initialize()
    {
        foreach (Type prodType in System.Reflection.Assembly.GetExecutingAssembly().GetTypes()
            .Where(prodType => prodType.GetInterfaces().Contains(typeof(IProduct))))
        {
            ProductTypes.Add(prodType);
        }
    }
    /// <summary>
    /// Factory Get function.
    /// </summary>
    /// <typeparam name="T">Generic implementing IProduct.</typeparam>
    /// <returns>Instance of the generic implementing IProduct.</returns>
    public static T GetProduct<T>() where T : IProduct, new()
    {
        var productType = ProductTypes.Where(x => x.Name.Equals(typeof(T).Name)).FirstOrDefault();
        if (productType is null) return default;
        return (T)Activator.CreateInstance(productType);
    }
}
/// <summary>
/// Entrypoint class.
/// </summary>
public static class Program
{
    /// <summary>
    /// Entrypoint method.
    /// </summary>
    public static void Main(string[] args)
    {
        // Initialize the list of product types.
        ProductFactory.Initialize();
        // Get an apple.
        var apple = ProductFactory.GetProduct<Apple>();
        // Get a pear.
        var pear = ProductFactory.GetProduct<Pear>();
    }
}
...