piątek, 6 lipca 2012

[Wzorce projektowe] Simple Factory, Abstract Factory

Analogia z życia:

Automat do napojów wyrzuca puszki takich samych rozmiarów z napojami różnych producentów. Decyzja o tym, którą puszkę zwrócić podejmowana jest w momencie, gdy użytkownik naciśnie odpowiednie przyciski i wrzuci odpowiednie monety. Całym procesem przeliczania oraz wybrania żądanego napoju zajmuje się automat.




Zastosowanie:

Fabryk używamy, kiedy chcemy oddzielić proces tworzenia obiektu od podejmowania decyzji o tym, który obiekt chcemy utworzyć. Znacznie ułatwia to rozszerzanie możliwości podczas dalszego rozwoju oprogramowania. Fabryki bywają także użyteczne, gdy informacje o tym, który obiekt mamy utworzyć przechowywane są poza programem, na przykład w bazie danych, pliku .xml etc. Zatem warto stosować fabryki, gdy nie jesteśmy pewni, której konkretnej implementacji danego interfejsu będziemy w danym miejscu potrzebowali. Często w kodzie może się pojawić sporo wyrażeń typu if-else lub switch podczas tworzenia obiektów. Można je również zastąpić fabryką.

Simple Factory:

Pierwsza wersja fabryki ma za zadanie enkapsulację tworzenia obiektów. Decyzja o tym, który obiekt ma zostać zbudowany może zostać podjęta w czasie trwania programu np. na podstawie pliku konfiguracyjnego. Pobranie obiektu odbywa się za pomocą metody GetInstance z parametrem typu string, skojarzonym z typem przez dot Netowe Reflection.


public interface IDrink
    {
        string GetName();
    }

    public class CocaCola : IDrink
    {
        public string GetName()
        {
            return "Coca - Cola";
        }
    }

    public class Pepsi : IDrink
    {
        public string GetName()
        {
            return "Pepsi";
        }
    }

    public class Sprite : IDrink
    {
        public string GetName()
        {
            return "Sprite";
        }
    }
public class DrinkFactory
    {
        private Dictionary<string, Type> _drinks;

        public DrinkFactory()
        {
            LoadDrinks();
        }

        public void LoadDrinks()
        {
            _drinks = new Dictionary<string, Type>();
            var types = Assembly.GetExecutingAssembly().GetTypes();
            foreach (var type in types)
            {
                if(type.GetInterface(typeof(IDrink).ToString())!= null)
                {
                    _drinks.Add(type.Name,type);
                }
            }
        }

        public IDrink GetInstance(string typeName)
        {
            foreach (KeyValuePair<string, Type> pair in _drinks)
            {
                if (pair.Key.ToLower().Contains(typeName.ToLower()))
                    return Activator.CreateInstance(pair.Value) as IDrink;
            }
            throw new NotImplementedException();
        }
    }
 class Program
    {
        static void Main(string[] args)
        {
            var factory = new DrinkFactory();

            IDrink drink = factory.GetInstance("Cola");
            Console.WriteLine(drink.GetName());
            drink = factory.GetInstance("pepsi");
            Console.WriteLine(drink.GetName());
        }
    }

Abstract Factory :

Fabryka abstrakcyjna zapewnia jedynie interfejs do tworzenia rodzin powiązanych ze sobą pewien sposób obiektów. Konkretne fabryki, będące implementacjami fabryki abstrakcyjnej umożliwiają tworzenie całych rodzin obiektów w zależności od parametru. Jedna fabryka może tym razem tworzyć wiele obiektów za pomocą różnych metod. Sposób tworzenia obiektów wewnątrz konkretnej fabryki może być całkowicie dowolny.




    public interface ICar
    {
        Engine Engine { get; set; }
        string Name { get; set; }
    }

    public class VWGolf : ICar
    {
        public Engine Engine { get; set; }

        public string Name
        {
            get { return "Volkswagen Golf"; }
            set { throw new NotImplementedException(); }
        }
    }

    public class FordFocus : ICar
    {
        public Engine Engine { get; set; }

        public string Name
        {
            get { return "Ford Focus"; }
            set { throw new NotImplementedException(); }
        }
    }
 abstract public class Engine
    {
        public int Capacity { get; set; }
    }

    public class GasEngine : Engine
    {
        public GasEngine()
        {
            Capacity = 30;
        }
    }

    public class PetrolEngine : Engine
    {
        public PetrolEngine()
        {
            Capacity = 50;
        }

    }
    public abstract class CarAbstractFactory
    {
        public abstract ICar CreateAutoWithPetrolEngine();
        public abstract ICar CreateAutoWithGasEngine();
    }

    public class VWGolfFactory : CarAbstractFactory
    {
        private ICar BaseCreate()
        {
            return new VWGolf();
        }

        public override ICar CreateAutoWithPetrolEngine()
        {
            var car = BaseCreate();
            car.Engine = new PetrolEngine();
            return car;
        }

        public override ICar CreateAutoWithGasEngine()
        {
            var car = BaseCreate();
            car.Engine = new GasEngine();
            return car;
        }
    }

    public class FordFocusFactory : CarAbstractFactory
    {

        public override ICar CreateAutoWithPetrolEngine()
        {
            var car = new FordFocus();
            car.Engine = new PetrolEngine();
            return car;
        }

        public override ICar CreateAutoWithGasEngine()
        {
            var car = new FordFocus();
            car.Engine = new GasEngine();
            return car;
        }
    }
static void Main(string[] args)
        {
            CarAbstractFactory factory = LoadFactory();
            var car = factory.CreateAutoWithGasEngine();
            Console.WriteLine(car.Name);
            Console.WriteLine(car.Engine.Capacity);
        }

        public static CarAbstractFactory LoadFactory()
        {
            Random rnd = new Random();
            if (rnd.Next() % 2 == 0)
                return new VWGolfFactory();
            return new FordFocusFactory();
        }

Brak komentarzy:

Prześlij komentarz