Рефакторинг двух основных классов - PullRequest
1 голос
/ 16 сентября 2008

Как бы вы провели рефакторинг этих двух классов, чтобы абстрагироваться от сходства? Абстрактный класс? Простое наследство? Как бы выглядел рефакторированный класс (классы)?

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;
        }
    }
}

Ответы [ 7 ]

2 голосов
/ 16 сентября 2008

Зависит от того, что если они не собираются делать намного больше, я бы, вероятно, оставил их как есть - ИМХО выделение вещей, вероятно, будет более сложным, в этом случае.

0 голосов
/ 16 сентября 2008

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

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));
    }
}
0 голосов
/ 16 сентября 2008
  1. Создать базовый базовый класс (например, AbstractCode<T>)
  2. добавить абстрактные методы, такие как

    protected T GetConstructor(string code);
    
  3. переопределить в базовых классах, таких как

    protected override RegionCode GetConstructor(string code)
    {
        return new RegionCode(code);
    }
    
  4. Наконец, сделайте то же самое с string GetIsoName(string code), например

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

Это будет рефакторинг обоих. Крис Кимптон поднимает важный вопрос о том, стоит ли это усилий.

0 голосов
/ 16 сентября 2008

Я уверен, что есть лучшее решение на основе генериков. Но все же дал ему шанс.

РЕДАКТИРОВАТЬ: Как говорится в комментарии, статические методы не могут быть переопределены, поэтому одним из вариантов будет сохранение их и использование объектов TwoLetterCode и их приведение, но, как уже заметил другой человек, это довольно бесполезно.

Как насчет этого?

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);
    }
}
0 голосов
/ 16 сентября 2008

Эти двое, в том виде, в каком они есть, не будут хорошо проводить рефакторинг из-за статических методов.

Вы должны либо получить какой-то фабричный метод для базового класса, который возвращает тип этого базового класса (который впоследствии будет нуждаться в приведении), либо вам понадобится какой-то дополнительный вспомогательный класс.

Учитывая количество дополнительного кода и последующее приведение к соответствующему типу, оно того не стоит.

0 голосов
/ 16 сентября 2008

Вы можете объединить их в класс Locale, который хранит как код языка, так и код региона, имеет средства доступа для региона и языка, а также одну функцию синтаксического анализа, которая также допускает строки типа "en_gb" ...

Вот как я видел, как локали обрабатываются в различных рамках.

0 голосов
/ 16 сентября 2008

Это довольно простой вопрос и для меня пахнет ужасно домашним заданием.

Очевидно, что вы можете увидеть общие биты в коде, и я вполне уверен, что вы можете попробовать это самостоятельно, поместив такие вещи в суперкласс.

...