Supported operation pattern structure

I have an abstract class "A", which has a property of the enumeration type "OutputType", and an abstract method () method, which should perform a certin calculation and output the result in double [] ** according to the value of OutputType.

I also have classes defined as D1, D2, D3 ... D20 derived from A, where each class Di implements the A () () method differently.

The problem is that not all OutputType values ​​(output types of calculations) are supported in every Di

For instance:

If the values ​​of the OutputType enumeration are "Scaled", "NonScaled" and "ConstantLength",

Di certificate can support "Scaled" and "NonScaled", but does not support "ConstantLength", and another Di can support all types of operations,

My question is:

What is the right design pattern to implement this behavior?

Please avoid the obvious "Throw if the OutputType property gets the value of an unsupported operation."



Edit

Expanding the question:

Is there a way to notify the user with intellisense of all supported operations, so the user should not use trial and error? (besides proper documentation)

0
source share
1 answer

, , , .

, .

, protected virtual , public, non-overridable Calculate overriden protected virtual?

public abstract class Calculation
{
    public Calculation()
    {
        // I store all overridable methods in a dictionary where keys
        // are the method names
        OverridableMethods = new Dictionary<string, Func<double[]>>()
        {
            { nameof(CalculateScaled), CalculateScaled },
            { nameof(CalculateNonScaled), CalculateNonScaled },
            { nameof(CalculateConstantLength), CalculateConstantLength }
        };


        // Then we get the first overriden method. If there're more
        // than one, it will pick the first occurence and others will be
        // discarded. It up to the developer to override just one.
        MethodInfo overridenMethod = OverridableMethods.Keys
                .Select(methodName => GetType().GetMethod(methodName, BindingFlags.Instance | BindingFlags.NonPublic))
                .FirstOrDefault(method => method.DeclaringType != typeof(Calculation));

        Contract.Assert(overridenMethod != null, "No calculation operation implementation has been provided");

        // So some method was overriden and I store the method name
        OverridenMethodName = overridenMethod.Name;
    }

    private string OverridenMethodName { get; }
    private Dictionary<string, Func<double[]>> OverridableMethods { get; }

    protected virtual double[] CalculateScaled() 
    {
        throw new NotImplementedException();
    }

    protected virtual double[] CalculateNonScaled() 
    {
        throw new NotImplementedException();
    }

    protected virtual double[] CalculateConstantLength()
    {
        throw new NotImplementedException();
    }

    // Calculate just access the overridable method dictionary
    // to get the overriden method encapsulated by a Func<double[]>
    // and I immediately call it!
    public double[] Calculate() => OverridableMethods[OverridenMethodName]();
}

public class SomeCalculation : Calculation
{
    protected override double[] CalculateScaled()
    {
        return new double[] { 22 };
    }
}

, !

    Calculation calculation = new SomeCalculation();

    // Prints out 22!
    Console.WriteLine(calculation.Calculate()[0]);
0

Source: https://habr.com/ru/post/1662784/


All Articles