Enum z atrybutem Flags

Załóżmy, że mamy zdefiniowaną stałą listę dostępnych pół formularza: imię, nazwisko, data urodzenia, płeć.
Pola te mogą być wyświetlane w różnych konfiguracjach, np. Imię z nazwiskiem, nazwisko z datą urodzenia lub tylko płeć. Pomijając fakt że z reguły typy wyliczeniowe łamią zasadę Open/Closed principle (http://pl.wikipedia.org/wiki/Zasada_otwarte-zamkni%C4%99te) i zastosowanie ich w tym przypadku może nie jest najlepszym pomysłem, to jednak chcąc pokazać jak zachowuje się typ Enum oznaczony atrybutem Flags pokuszę się o przygotowanie właśnie takiego przykładu.

    [Flags]
    public enum FieldType
    {
        None, //0000
        FirstName, //0001
        LastName, //0010
        DateOfBirth, //0100
        Gender //1000
    }

Ze względu na atrybut Flags, każda wartość typu wyliczeniowego odzwierciedla teraz flagę w postaci binarnej. Dzięki temu możemy posłużyć się bitowym operatorem OR (suma logiczna), w celu definicji jakie pola mają się pokazywać na formularzu, oraz AND (iloczyn logiczny) w celu określenia jakie flagi zostały wykorzystane.

Poniższy przykład definiuje pola imię, nazwisko i data urodzenia. Binarnie kombinacja tych flag przedstawia się jako: 0111.

DisplayHelper.Display(FieldType.FirstName | FieldType.LastName | FieldType.DateOfBirth);

Chcąc określić jakie flagi zostały wykorzystane, stosujemy operator AND.

    public class DisplayHelper
    {
        public static void Display(FieldType fieldType)
        {
            if (DetermineFieldType(fieldType, FieldType.FirstName))
                Console.WriteLine("Display First name field");

            if (DetermineFieldType(fieldType, FieldType.LastName))
                Console.WriteLine("Display Last name field");

            if (DetermineFieldType(fieldType, FieldType.DateOfBirth))
                Console.WriteLine("Display Date of birth field");

            if (DetermineFieldType(fieldType, FieldType.Gender))
                Console.WriteLine("Display gender field");
        }

        private static bool DetermineFieldType(FieldType fieldType, FieldType compareTo)
        {
            return (fieldType & compareTo) == compareTo;
        }
    }

W metodzie DetermineFieldType wykonywana jest operacja iloczynu logicznego (AND).
Chcąc określić, czy flaga 0111 (odpowiadająca zastosowaniu trzech typów: FirstName, LastName i DateOfBirth), przekazana jako parametr wywołania metody Display, zawiera w sobie np. pole FirstName, wykonywana jest operacja iloczynu logicznego (0111 AND 0001) = 0001, która potwierdza, że typ FirstName (0001) ma zostać wyświetlony na formularzu.

W .NET 4.0. do tego celu można wykorzystać metodę HasFlag() i metoda ta wygląda wówczas w ten sposób

        private static bool DetermineFieldType(FieldType fieldType, FieldType compareTo)
        {
            return fieldType.HasFlag(compareTo);
        }

Decorator Pattern

Zastosowanie wzorca Decorator na przykładzie produktu i ofert specjalnych.
Wzorzec ten pozwala nam na dynamiczną zmianę/rozszerzanie zachowania istniejących klas.

    public abstract class Item
    {
        public abstract int Id { get; set; }

        public abstract string Name { get; set; }

        public abstract decimal Price { get; set; }
    }

Klasa Product dziedziczy z naszej abstrakcyjnej klasy Item.

    public class Product : Item
    {
        public override int Id { get; set; }

        public override string Name { get; set; }

        public override decimal Price { get; set; }
    }

Definicja abstrakcyjnej klasy dekoratora dla typu Item, wraz z implementacją wyliczenia nowej ceny dla produktu.

    public abstract class ProductDecoratorBase : Item
    {
        private readonly Item _item;

        public decimal Discount { get; protected set; }

        public ProductDecoratorBase(Item item)
        {
            _item = item;
        }

        public override int Id
        {
            get
            {
                return _item.Id;
            }
            set
            {
                _item.Id = value;
            }
        }

        public override string Name
        {
            get
            {
                return _item.Name;
            }
            set
            {
                _item.Name = value;
            }
        }

        public override decimal Price
        {
            get
            {
                var newPrice = _item.Price - Discount;

                return newPrice < 0 ? 0 : newPrice;
            }
            set
            {
                _item.Price = value;
            }
        }
    }

Definicja klasy SpecialOffer na bazie naszego dekoratora z promocyjnym upustem w wysokości 500zł.

    public class SpecialOffer : ProductDecoratorBase
    {       
        public SpecialOffer(Item product) : base(product)
        {
            Discount = 500;   
        }               
    }

Definicja klasy WeekendSpecialOffer na bazie naszego dekoratora z promocyjnym upustem w wysokości 750zł.

    public class WeekendSpecialOffer : ProductDecoratorBase
    {        
        public WeekendSpecialOffer(Item item) : base(item) 
        {
            Discount = 750;
        }
    }

Poniżej przykład zastosowania zaimplementowanego wzorca.

    class Program
    {
        static void Main(string[] args)
        {
            //Decorator
            Item laptop = new Product { Id = 1, Name = "Laptop", Price = 2545M };

            SpecialOffer specialOfferForMouse = new SpecialOffer(laptop);
            Console.WriteLine("Special price {0}", specialOfferForMouse.Price);

            WeekendSpecialOffer weekendOffer = new WeekendSpecialOffer(laptop);
            Console.WriteLine("Special weekend price {0}", weekendOffer.Price);

            Console.WriteLine("Original price {0}", laptop.Price);
        }
    }

Wynik działania aplikacji:

Zastosowanie JavaScript Revealing Module Pattern

Podczas pisania aplikacji z zastosowaniem JavaScript bardzo przypadł mi do gustu wzorzec Revealing Module Pattern do uporządkowania i ustrukturyzywania kodu. Poniżej przykład

var dataService = function () {
    var serviceBase = '/Service/',

    getTravels = function (callback) {
        $.getJSON(serviceBase + 'GetTravels', function (data) {
            callback(data);
        });
    },

    getPlacesInTravel = function (travelId, callback) {
        $.getJSON(serviceBase + 'GetPlacesInTravel', { travelId: travelId }, function (data) {
            callback(data);
        });
    },

    getPlaces = function (callback) {
        $.getJSON(serviceBase + 'GetPlaces', function (data) {
            callback(data);
        });
    };

    return {
        getTravels: getTravels,
        getPlacesInTravel: getPlacesInTravel,        
        getPlaces: getPlaces
    };
} ();

Dzięki temu wzorcowi w bardzo przejrzysty sposób możemy enkapsulować logikę związaną z jakimś zagadnieniem w jednym miejscu i dodatkowo mieć wpływ, dzięki słowu kluczowemy return, jakie metody będą publiczne.

Następnie samo wywołanie sprowadza się do następującego kawałka kodu

dataService.getPlacesInTravel(value, renderPlacesInTravel);