All we do is looking for some way to fulfill our needs.

sobota, 11 czerwca 2011

Tagged under: , ,

Naturalny porządek refaktoryzacji pod lupą cz. 3 Extract Method

W następnym kroku przyglądamy się odpowiedzialnościom poszczególnych klas oraz metodom, pod kątem dopasowania do odpowiedzialności klasy. Najlepiej przeanalizuj wszystkie metody oraz pogrupuj je pod kątem wykonywania podobnych operacji. Szukamy dla nich miejsca w innych klasach lub w nowej klasie. Pamiętaj: jeśli w danej klasie istnieje znacząca metoda prywatna (dłuższa niż 3-4 wiersze), to metoda ta powinna znaleźć się w innej klasie.
W naszym przykładzie metody głównie skupiają wokół pojedynczych operacji mających na celu zaciemnianie tekstu oraz zapewniającym wykonanie operacji z pewnym prawdopobieństwem. Możemy wyodrębnić odpowiadające tym operacjom klasy TextObfuscatorMethods oraz Probability.
Kod po tej zmianie mógłby wyglądać tak:
public class TextObfuscator
{
    // ...
    public string Obfuscate(string text)
    {
        List<TextPart> parts = methods.ParseTextForWordsAndNonWords(text);
        methods.ChangeWordsOrderRandomly(parts);
        methods.AddMeaninglessWordsRandomly(parts);
        methods.RemoveSeparators(parts);
        methods.AddSeparatorsRandomly(parts);
        methods.RemoveSpaces(parts);
        // ...
    }
}

public class TextObfuscatorMethods
{
    // ...
    public virtual void RemoveSpaces(List<TextPart> parts)
    {
        for (int i = 0; i < parts.Count; i++)
        {
            RemoveSpacesFromTextPart(parts, i);
            RemoveTextPartIfEmpty(parts, i);
        }
    }

    private static void RemoveSpacesFromTextPart(List<TextPart> parts, int i)
    {
        parts[i] = parts[i].ReplaceContents(" ", "");
    }

    public virtual void RemoveSeparators(List<TextPart> parts)
    {
        for(int i = 0; i < parts.Count; i++)
        {
            RemoveSeparatorsFromTextPart(parts, i);
            RemoveTextPartIfEmpty(parts, i);
        }
    }

    public virtual void AddSeparatorsRandomly(List<TextPart> parts)
    {
        for (int i = 0; i < parts.Count; i++)
        {
            if (ShouldAddSeparator())
            {
                parts.Insert(i, TextPart.NewSeparator(DrawSeparator())); i++;
            }
        }
    }

    private bool ShouldAddSeparator()
    {
        return probability.ShouldBeDone(ADDING_SEPARATOR_PROBABILITY);
    }
    // ...
}

public class Probability
{
    private Random random = new Random();

    public bool ShouldBeDone(double probability)
    {
        if (probability < 0.0 || probability > 1.0)
        {
            throw new ProbabilityException("Probability should be in range [0.0, 0.1]");
        }

        return random.NextDouble() < probability;
    }
}

0 komentarze: