Modello astratto di progettazione industriale

1

Ho bisogno di aiuto con un design pattern factory astratto. Ho e motore di calcolo che calcola per diversi canali come captive, captiveTemplate o Headquarter e in futuro può essere aggiunto un canale diverso. In allegato c'è il disegno su come sto configurando il pattern:

Il problema è che alcuni elementi sono calcolati solo per canali specifici e alcuni elementi calcolati per tutti i tipi di canali. Ad esempio, CaptiveManagementFee calcola solo in CaptiveCalculatorFactory e InterestMargin calcolati solo in HeadQuarterFactory ma ServiceMarkup deve essere calcolato in tutti i tipi di calculatorFactory. dovrei progettare le mie classi per risolvere questo problema?

    
posta Fikret Asma 11.05.2017 - 09:03
fonte

1 risposta

0

Forse qualcosa sulla falsariga di:

public class CalculatorItem
{
}

public class CaptiveManagementFee : CalculatorItem
{
}

public class InterestMargin : CalculatorItem
{
}

public class ServiceMarkup : CalculatorItem
{
}

public interface ICalculator
{
    void Calculate(CalculatorItem item);
}

public interface ICalculator<TCalculatorItem> : ICalculator
    where TCalculatorItem : CalculatorItem
{
    void Calculate(TCalculatorItem item);
}

public class CalculatorBase : ICalculator
{
    protected void Witness(string method, object item)
    {
        Console.WriteLine($"{GetType()}.{method}({item.GetType()})");
    }

    #region ICalculator
    public void Calculate(CalculatorItem item)
    {
        if (item == null)
        {
            throw new ArgumentNullException("undecidable item type for null", nameof(item));
        }
        var itemType = item.GetType();
        var specialized = GetType().GetMethod(nameof(Calculate), new[] { itemType });
        if (specialized == null)
        {
            throw new ArgumentException($"unsupported item type: {itemType}", nameof(item));
        }
        specialized.Invoke(this, new object[] { item });
    }
    #endregion
}

public class CaptiveCalculator : CalculatorBase,
    ICalculator<CaptiveManagementFee>,
    ICalculator<ServiceMarkup>
{
    protected virtual void CalculateFee(CaptiveManagementFee item)
    {
        Witness(nameof(CalculateFee), item);
    }

    protected virtual void CalculateMarkup(ServiceMarkup item)
    {
        Witness(nameof(CalculateMarkup), item);
    }

    #region ICalculator<CaptiveManagementFee>
    public void Calculate(CaptiveManagementFee item)
    {
        CalculateFee(item);
    }
    #endregion

    #region ICalculator<ServiceMarkup>
    public void Calculate(ServiceMarkup item)
    {
        CalculateMarkup(item);
    }
    #endregion
}

public class HeadquarterCalculator : CalculatorBase,
    ICalculator<InterestMargin>,
    ICalculator<ServiceMarkup>
{
    protected virtual void CalculateMargin(InterestMargin item)
    {
        Witness(nameof(CalculateMargin), item);
    }

    protected virtual void CalculateMarkup(ServiceMarkup item)
    {
        Witness(nameof(CalculateMarkup), item);
    }

    #region ICalculator<InterestMargin>
    public void Calculate(InterestMargin item)
    {
        CalculateMargin(item);
    }
    #endregion

    #region ICalculator<ServiceMarkup>
    public void Calculate(ServiceMarkup item)
    {
        CalculateMarkup(item);
    }
    #endregion
}

public class CalculatorFactory
{
    private static Type[] CalculatorTypes =
        new[] { typeof(CaptiveCalculator), typeof(HeadquarterCalculator) };

    public ICalculator<TCalculatorItem> CreateCalculator<TCalculatorItem>()
        where TCalculatorItem : CalculatorItem
    {
        var found =
            CalculatorTypes.
            Single // (throws if we don't find exactly *one* matching type)
            (
                type =>
                    typeof(ICalculator<>).MakeGenericType(typeof(TCalculatorItem)).IsAssignableFrom(type)
            );
        return (ICalculator<TCalculatorItem>)Activator.CreateInstance(found);
    }
}

class Program
{
    static void Main(string[] args)
    {
        var calcFactory = new CalculatorFactory();

        var headQuarterCalc = calcFactory.CreateCalculator<InterestMargin>();
        headQuarterCalc.Calculate(new InterestMargin());
        //headQuarterCalc.Calculate(new CaptiveManagementFee()); // throws an exception (unsupported item type)
        headQuarterCalc.Calculate(new ServiceMarkup()); // late-bound, dispatched via ICalculator.Calculate(CalculatorItem)

        var captiveCalc = calcFactory.CreateCalculator<CaptiveManagementFee>();
        captiveCalc.Calculate(new CaptiveManagementFee());
        //captiveCalc.Calculate(new InterestMargin()); // throws an exception (unsupported item type)
        captiveCalc.Calculate(new ServiceMarkup()); // late-bound, dispatched via ICalculator.Calculate(CalculatorItem)

        //var ambiguousCalc = calcFactory.CreateCalculator<ServiceMarkup>(); // throws an exception

        Console.ReadKey();
    }
}

Questo è un po 'troppo di norma a mio gusto (YMMV), ma non posso davvero pensare a nulla di più semplice considerando le tue esigenze, prese così com'è.

'Spero che questo aiuti.

    
risposta data 12.05.2017 - 09:57
fonte