简体   繁体   中英

How to refactor two methods?

I have two methods with a similar signature (ChooseChamfer and ChooseFillet). These methods have an extensive structure if .. else. (I brought a simplified version), where the methods are invoked (CreateChamfer and CreateFillet). How can I make refactoring code in a single method?

private void ChooseChamfer(string featureType, double diameter, double distance, string str1, string str2)
{
    if (featureType.Contains("F"))
    {
        CreateChamfer(diameter, 
            distance,
            -double.Parse(str1, System.Globalization.CultureInfo.InvariantCulture),
             double.Parse(str2, System.Globalization.CultureInfo.InvariantCulture));
    }
    else if (featureType.Contains("L"))
    {
        CreateChamfer(diameter, 
            distance,
            double.Parse(str1, System.Globalization.CultureInfo.InvariantCulture),
           -double.Parse(str2, System.Globalization.CultureInfo.InvariantCulture));
    }
}

private void ChooseFillet(string featureType, double diameter, double distance, string str1)
{
    if (featureType.Contains("F"))
    {
        CreateFillet(diameter, 
            distance,
            -double.Parse(str1, System.Globalization.CultureInfo.InvariantCulture));
    }
    else if (featureType.Contains("L"))
    {
        CreateFillet(diameter, 
            distance,
            double.Parse(str1, System.Globalization.CultureInfo.InvariantCulture));
    }
}

private void CreateChamfer(double diameter, double distance, double str1, double str2)
{
    //Draw Chamfer
}

private void CreateFillet(double diameter, double distance, double str1)
{
    //Draw Fillet
}

Thank you in advance.

I don't know how deep you want to cut, but whenever I see if/else complexity like that, I think Factory and specialists. This could be sliced 100 different ways, but from what I understand from the potential complexity, I think basing a factory on FeatureType would be better than basing it on Chamfer/Fillet:

abstract class GraphicAttributes
{
    public double Diameter { get; protected set; }
    public double Distance { get; protected set; }
    public double Str1 { get; protected set; }
    public double? Str2 { get; protected set; }

    public GraphicAttributes(double diameter, double distance, string str1, string str2)
    {
        // load all attributes plain-vanilla - let the subclasses adjust as necessary
        Diameter = diameter;
        Distance = distance;
        Str1 = double.Parse(str1, System.Globalization.CultureInfo.InvariantCulture);
        Str2 = String.IsNullOrEmpty(str2)
            ? new Nullable<double>()
            : double.Parse(str2, System.Globalization.CultureInfo.InvariantCulture);
    }
}

class FeatureTypeF : GraphicAttributes
{
    public FeatureTypeF(double diameter, double distance, string str1, string str2)
        : base(diameter, distance, str1, str2)
    {
        Str1 = -Str1;
    }
}

class FeatureTypeL : GraphicAttributes
{
    public FeatureTypeL(double diameter, double distance, string str1, string str2)
        : base(diameter, distance, str1, str2)
    {
        if (Str2.HasValue)
            Str2 = new Nullable<double>(-(Str2.Value));
    }
}

class GraphicAttributeFactory
{
    public static GraphicAttributes GetGraphicAttributes(string featureType, double diameter, double distance, string str1, string str2)
    {
        if (featureType.Contains("F"))
            return new FeatureTypeF(diameter, distance, str1, str2);

        if (featureType.Contains("L"))
            return new FeatureTypeL(diameter, distance, str1, str2);

        // add more implementations here

        throw new Exception("Unexpected featureType!");
    }
}

// and then your final method looks like:

private void Choose(string featureType, double diameter, double distance, string str1, string str2)
{
    GraphicAttributes ga = GraphicAttributeFactory.GetGraphicAttributes(featureType, diameter, distance, str1, str2);

    if (ga.Str2.HasValue)
        CreateChamfer(ga.Diameter, ga.Distance, ga.Str1, ga.Str2.Value);
    else
        CreateFillet(ga.Diameter, ga.Distance, ga.Str1);
}

The caller would have to explicitly nullify the extra param:

Choose("__L_", 12.0, 5.0, "123", "456"); // chamfer
Choose("__F_", 12.0, 5.0, "123", null);  // fillet

That part is kind of clumsy; it could be expanded to use 'params string'.

Also, it would be great if you could go deeper and refactor the Create..() methods into one that takes the GraphicAttribute instance directly.

At any rate, the real idea is putting the specific treatment of the attributes into specialty classes, each knowing how to handle it's own situation, and then a factory that knows how to choose the right implementation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM