wtorek, 10 lipca 2012

[Wzorce projektowe] Flyweight

Analogia z życia:

Chodząc do szkoły codziennie rano pakujemy do plecaka zeszyty. Mając pięć godzin lekcyjnych, w tym dwie godziny języka polskiego, zabierzemy cztery zeszyty (prawdopodobnie częściowo już zapisane). Moglibyśmy dla każdej lekcji każdego przedmiotu zakładać nowy zeszyt, ale byłoby to kosztowne zupełnie niepotrzebne. Każda nowa lekcja jest identyfikowana przez stronę, na której się znajduje i przez rodzaj zeszytu w jakim jest zapisana. Oczywiście do różnych przedmiotów mamy do dyspozycji różne zeszyty (w linie, kratkę, gładkie). Zawsze jednak jeden zeszyt może nam posłużyć do zapisywania lekcji przez cały semestr z danego przedmiotu.



Zastosowanie:

Wzorzec Flyweight znajduje zastosowanie wszędzie tam, gdzie mamy do czynienia z dużą ilością obiektów tego samego typu, co wiąże się z dużymi kosztami pamięciowymi przy przechowywaniu. Dzięki niemu możemy używać tego samego obiektu w wielu sytuacjach, przy zachowaniu całej elastyczności związanej z korzystaniem z niego, co powoduje, że zamiast używać np. setek instancji możemy skorzystać zaledwie z kilku. Aby było to możliwe, musimy wyciągnąć z obiektów ich zewnętrzny stan poza obiekt, przy zachowaniu wewnętrznych właściwości. Dzięki temu aplikacja nie zależy od tożsamości konkretnych instancji obiektów, mimo iż podchodząc w 100% obiektowo do modelowania zagadnienia musielibyśmy utworzyć o wiele więcej obiektów.

Zasada działania:

Na początku tworzymy pewien interfejs reprezentujący rodzinę obiektów. Następnie modelujemy różnice w obiektach poprzez konkretne implementacje tego interfejsu. W miejscu, w którym pojawia się zapotrzebowanie na obiekty posługujemy się fabryką, która zwraca już istniejące instancje i wywołuje na nich pewne akcje. Zewnętrzne cechy obiektów przekazywane są przez parametr.

Przykład implementacyjny:

  public interface ISoldier
    {
        int Damage { get; set; }
        void Shoot(int x, int y);
    }

    public class LightInfantry : ISoldier
    {
        public LightInfantry()
        {
            Damage = 20;
        }

        public int Damage { get; set; }

        public void Shoot(int x, int y)
        {
            Console.WriteLine(String.Format
                ("Shooting from ({0},{1}), done {2} damage",x,y,Damage));
        }
    }

    public class Artillery : ISoldier
    {
        public Artillery()
        {
            Damage = 200;
        }

        public int Damage { get; set; }

        public void Shoot(int x, int y)
        {
            Console.WriteLine(String.Format
                ("Shooting from ({0},{1}), done {2} damage", x, y, Damage));
        }
    }
public class SoldierFactory
    {
        private Dictionary<string, ISoldier> _instances =
            new Dictionary<string, ISoldier>();

        
        public ISoldier GetSoldier(string typeName)
        {
            switch (typeName)
            {
                case "LightInfantry":
                    if (!_instances.ContainsKey(typeName))
                        _instances.Add(typeName, new LightInfantry());
                    return _instances[typeName];
                case "Artillery" :
                    if (!_instances.ContainsKey(typeName))
                        _instances.Add(typeName, new Artillery());
                    return _instances[typeName];
                default:
                    throw new NotImplementedException();
            }
        }
    }
class Program
    {
        static void Main(string[] args)
        {
            CreateArmyAndAttack();
            Console.Read();
        }

        public static void CreateArmyAndAttack()
        {
            Random r = new Random();
            var factory = new SoldierFactory();
            for (int i = 0; i < 1000; i++)
            {
                factory.GetSoldier("LightInfantry")
                    .Shoot(r.Next() % 100, r.Next() % 100);
            }
            for (int i = 0; i < 100; i++)
            {
                factory.GetSoldier("Artillery")
                    .Shoot(r.Next() % 20, r.Next() % 100);
            }
        }
    }

Brak komentarzy:

Prześlij komentarz