Pregunta

¿Cómo refactorizarías estas dos clases para abstraer las similitudes?¿Una clase abstracta?¿Herencia sencilla?¿Cómo serían las clases refactorizadas?

public class LanguageCode
{
    /// <summary>
    /// Get the lowercase two-character ISO 639-1 language code.
    /// </summary>
    public readonly string Value;

    public LanguageCode(string language)
    {
        this.Value = new CultureInfo(language).TwoLetterISOLanguageName;
    }

    public static LanguageCode TryParse(string language)
    {
        if (language == null)
        {
            return null;
        }

        if (language.Length > 2)
        {
            language = language.Substring(0, 2);
        }

        try
        {
            return new LanguageCode(language);
        }
        catch (ArgumentException)
        {
            return null;
        }
    }
}

public class RegionCode
{
    /// <summary>
    /// Get the uppercase two-character ISO 3166 region/country code.
    /// </summary>
    public readonly string Value;

    public RegionCode(string region)
    {
        this.Value = new RegionInfo(region).TwoLetterISORegionName;
    }

    public static RegionCode TryParse(string region)
    {
        if (region == null)
        {
            return null;
        }

        if (region.Length > 2)
        {
            region = region.Substring(0, 2);
        }

        try
        {
            return new RegionCode(region);
        }
        catch (ArgumentException)
        {
            return null;
        }
    }
}
¿Fue útil?

Solución

A menos que tenga una buena razón para refactorizar (porque va a agregar más clases como éstas en un futuro cercano), la penalización de cambiar el diseño por un ejemplo tan pequeño y artificial superaría la ganancia en mantenimiento o gastos generales en este escenario.De todos modos, aquí hay un posible diseño basado en expresiones genéricas y lambda.

public class TwoLetterCode<T>
{
    private readonly string value;

    public TwoLetterCode(string value, Func<string, string> predicate)
    {
        this.value = predicate(value);
    }

    public static T TryParse(string value, Func<string, T> predicate)
    {
        if (value == null)
        {
            return default(T);
        }

        if (value.Length > 2)
        {
            value = value.Substring(0, 2);
        }

        try
        {
            return predicate(value);
        }
        catch (ArgumentException)
        {
            return default(T);
        }
    }

    public string Value { get { return this.value; } }
}

public class LanguageCode : TwoLetterCode<LanguageCode>  {
    public LanguageCode(string language)
        : base(language, v => new CultureInfo(v).TwoLetterISOLanguageName)
    {
    }

    public static LanguageCode TryParse(string language)
    {
        return TwoLetterCode<LanguageCode>.TryParse(language, v => new LanguageCode(v));
    }
}

public class RegionCode : TwoLetterCode<RegionCode>
{
    public RegionCode(string language)
        : base(language, v => new CultureInfo(v).TwoLetterISORegionName)
    {
    }

    public static RegionCode TryParse(string language)
    {
        return TwoLetterCode<RegionCode>.TryParse(language, v => new RegionCode(v));
    }
}

Otros consejos

Depende, si no van a hacer mucho más, entonces probablemente los dejaría como están; en mi humilde opinión, factorizar cosas probablemente sea más complejo, en este caso.

Esta es una pregunta bastante simple y para mí huele terriblemente a tarea.

Obviamente puedes ver los bits comunes en el código y estoy bastante seguro de que puedes intentarlo tú mismo colocando esas cosas en una superclase.

Tal vez podrías combinarlos en un Locale La clase, que almacena tanto el código de idioma como el código de región, tiene descriptores de acceso para Región e Idioma más una función de análisis que también permite cadenas como "en_gb"...

Así es como he visto que se manejan las configuraciones regionales en varios marcos.

Estos dos, tal como están, no se refactorizarán bien debido a los métodos estáticos.

Terminaría con algún tipo de método de fábrica en una clase base que devuelve un tipo de esa clase base (que posteriormente necesitaría conversión) o necesitaría algún tipo de clase auxiliar adicional.

Dada la cantidad de código adicional y la posterior conversión al tipo apropiado, no vale la pena.

  1. Cree una clase base genérica (p. ej. AbstractCode<T>)
  2. agregar métodos abstractos como

    protected T GetConstructor(string code);
    
  3. anular en clases base como

    protected override RegionCode GetConstructor(string code)
    {
        return new RegionCode(code);
    }
    
  4. Finalmente haz lo mismo con string GetIsoName(string code), p.ej

    protected override GetIsoName(string code)
    {
        return new RegionCode(code).TowLetterISORegionName;
    }
    

Eso refactorizará ambos.Chris Kimpton plantea la importante pregunta de si el esfuerzo vale la pena.

Estoy seguro de que existe una mejor solución basada en genéricos.Pero aun así lo intenté.

EDITAR:Como dice el comentario, los métodos estáticos no se pueden anular, por lo que una opción sería conservarlos y utilizar objetos TwoLetterCode y emitirlos, pero, como ya ha señalado otra persona, eso es bastante inútil.

¿Qué tal esto?

public class TwoLetterCode {
    public readonly string Value;
    public static TwoLetterCode TryParseSt(string tlc) {
        if (tlc == null)
        {
            return null;
        }

        if (tlc.Length > 2)
        {
            tlc = tlc.Substring(0, 2);
        }

        try
        {
            return new TwoLetterCode(tlc);
        }
        catch (ArgumentException)
        {
            return null;
        }
    }
}
//Likewise for Region
public class LanguageCode : TwoLetterCode {
    public LanguageCode(string language)
    {
        this.Value = new CultureInfo(language).TwoLetterISOLanguageName;
    }
    public static LanguageCode TryParse(string language) {
        return (LanguageCode)TwoLetterCode.TryParseSt(language);
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top