2008-09-16 13 views
1

Wie würden Sie diese beiden Klassen umgestalten, um die Ähnlichkeiten zu abstrahieren? Eine abstrakte Klasse? Einfache Vererbung? Wie würden die umstrukturierten Klassen aussehen?Refactoring zwei grundlegende Klassen

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

Antwort

0

Es sei denn, Sie haben einen starken Grund für das Refactoring (weil Sie in naher Zukunft weitere Klassen hinzufügen werden), würde die Strafe, den Entwurf für solch ein kleines und künstliches Beispiel zu ändern, den Gewinn an Wartung oder Overhead in diesem Bereich überwinden Szenario. Irgendwie ist hier ein mögliches Design basierend auf generischen und Lambda-Ausdrücken.

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

Es hängt davon ab, ob sie sind nicht viel mehr tun würde, dann würde ich wahrscheinlich sie lassen wie es ist - IMHO Sachen Ausklammern ist wahrscheinlich komplexer, in diesem Fall sein.

0

Das ist eine ziemlich einfache Frage und riecht mir ehrfurchtsvoll wie eine Hausaufgabe.

Sie können natürlich die gemeinsamen Bits im Code sehen und ich bin mir ziemlich sicher, dass Sie selbst einen Versuch machen können, indem Sie solche Dinge in eine Superklasse stecken.

0

Sie könnten sie vielleicht in eine Locale Klasse kombinieren, die sowohl Sprachcode und Regionalcode speichert, hat Accessoren für Region und Sprache plus eine Parse-Funktion, die auch für Zeichenketten wie „en_gb“ erlaubt ...

Das ist Wie ich gesehen habe, dass Gebietsschemata in verschiedenen Frameworks behandelt werden.

0

Diese zwei, wie sie stehen, werden wegen der statischen Methoden nicht gut umgestalten.

Sie würden entweder mit einer Art Factory-Methode für eine Basisklasse enden, die einen Typ dieser Basisklasse zurückgibt (der anschließend umgewandelt werden müsste), oder Sie benötigen eine zusätzliche Hilfsklasse.

Angesichts der Menge an zusätzlichen Code und anschließende Gießen auf den entsprechenden Typ, es ist es nicht wert.

0

Ich bin sicher, dass es eine bessere Generika-basierte Lösung gibt. Aber trotzdem gab es eine Chance.

EDIT: Wie der Kommentar sagt, können statische Methoden nicht eine außer Kraft gesetzt werden, so Option wäre es zu behalten und verwenden TwoLetterCode Objekte um und wirft sie, aber, wie eine andere Person hat bereits darauf hingewiesen, dass ziemlich nutzlos .

Wie wäre es damit?

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

Leider funktioniert das nicht gut, da Ihre TryParse-Methode nicht statisch ist. TryParse ist eine Factory-Methode, die ein neues LanguageCode- oder RegionCode-Objekt zurückgibt. In Ihrem Beispiel müssen Sie zuerst ein Objekt erstellen. Sie können die Basis TryParse nicht überschreiben, da sie statisch ist. –

+0

Hmm, eine neue Instanz von TwoLetterCode kann leider nicht erstellt werden, da sie abstrakt ist (siehe: return new TwoLetterCode (tlc)). Ich kann "abstract" aus TwoLetterCodes Klassen-Delcaration entfernen, aber das möchte ich nicht - nur geschützte Typen sollten in der Lage sein, einen TwoLetterCode zu erstellen. – core

0
  1. Erstellen Sie eine generische Basisklasse (zB AbstractCode<T>)
  2. hinzufügen abstrakte Methoden wie

    protected T GetConstructor(string code); 
    
  3. Überschreibung in Basisklassen wie

    protected override RegionCode GetConstructor(string code) 
    { 
        return new RegionCode(code); 
    } 
    
  4. Schließlich tun das gleiche mit string GetIsoName(string code), zB

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

dass die beiden Refactoring wird. Chris Kimpton wirft die wichtige Frage auf, ob sich der Aufwand lohnt.