Refaktoryzacja – Bool To Enum

Dziś mały przykład refaktoryzacji polegającej na zamianie flag bool na enum’a. Zdecydowałem się na ten krok gdyż nie lubię złożonych warunków if i tam gdzie można staram się je upraszczać. Poniżej klasa zawierająca dwa pola typu bool, którę odpowiadają za to jaka wersja pliku ma zostać wyeksportowana.

public class FileExport
{
    public bool Origin { get; set; }
    public bool Modified { get; set; }
    public void Export()
    {
        if (Origin && !Modified)
        {
            WriteLine("Exporting origin file version");
        }
        else if (!Origin && Modified)
        {
            WriteLine("Exporting modified file version");
        }
        else if (Origin && Modified)
        {
            WriteLine("Exporting origin&modified file version");
        }
        else
        {
            WriteLine("Nothing to export ....");
        }
    }
}

Co mi tutaj nie odpowiadało to klauzule if. Może zbyt mocno uprościłem ten przykład ale w kodzie produkcyjnym te klauzule były dość długie i mało czytelne. Zastanawiałem się także co będzie jak nastąpi wprowadzenie kolejnej flagi do warunku?
I tutaj przyszedł pomysł wprowadzenia typu enum, który uwzględniał by już kombinację tych flag i odpowiednio by je opisywał.

Krok #1 – Utworzenie typu enum

[Flags]
public enum VersionToExport
{
    None = 0,
    Origin = 1 << 1,
    Modified = 1 << 2,
    Both = Origin | Modified
}

Atrybut Flags umożliwia traktowanie takiego typu enum jako pola bitowego, które może być zbiorem kombinacji pól. Kolejne pola otrzymują wartość kolejnych potęg dwójki 0, 2, 4, 8, 16 …

Krok #2 – Przypisanie wartości

 Kolejnym etapem jest „zapalenie” odpowiednich bitów. Ja użyłem takiego rozwiązania:

public VersionToExport ExportVersion {get; set; }
public SetExportVersion()
{
ExportVersion = Origin ? VersionToExport.Origin : 0;
ExportVersion |= Modified ? VersionToExport.Modified : 0;
}
To tyle. Opcji None oraz Both nie musimy tutaj przypisywać. None jest domyślną wartością a Both jest z kolei kombinacją dwóch flag Origin i Modified. Zwracam tutaj uwagę na operator |=, który wykonuje operację bitową OR. x |=y jest odpowiednikiem x = x | y

Krok #3 – Użycie

I na koniec przykład jak uległa zmianie klauzula if. Można przy okazji zamienić ją na switch’a (Jakoś tak mam, że przy typach enum częściej używam instrukcji switch).

public void Export()
{
    switch (ExportVersion)
    {
        case VersionToExport.Origin:
            WriteLine("Exporting origin file version");
            break;
        case VersionToExport.Modified:
            WriteLine("Exporting modified file version");
            break;
        case VersionToExport.Both:
            WriteLine("Exporting origin&modified file version");
            break;
        default:
            WriteLine("Nothing to export ....");
            break;
    }
}

W całym tym rozwiązaniu chciałem pozbyć się różnych kombinacji true&false z klauzul if. Dodatkowo enum lepiej opisuje dany warunek przez co kod lepiej się czyta.