static void Main(string[] args)
        {
            #region Create Order
            Console.Write("Recipient Country: ");
            var recipientCountry = Console.ReadLine().Trim();

            Console.Write("Sender Country: ");
            var senderCountry = Console.ReadLine().Trim();

            Console.Write("Total Order Weight: ");
            var totalWeight = Convert.ToInt32(Console.ReadLine().Trim());

            var order = new Order
            {
                Recipient = new Address
                {
                    To      = "Filip Ekberg",
                    Country = recipientCountry
                },

                Sender = new Address
                {
                    To      = "Someone else",
                    Country = senderCountry
                },

                TotalWeight = totalWeight
            };

            order.LineItems.Add(new Item("CSHARP_SMORGASBORD", "C# Smorgasbord", 100m), 1);
            order.LineItems.Add(new Item("CONSULTING", "Building a website", 100m), 1);
            #endregion

            IPurchaseProviderFactory purchaseProviderFactory;

            var factoryProvider = new PurchaseProviderFactoryProvider();

            purchaseProviderFactory = factoryProvider.CreateFactoryFor(order.Sender.Country);

            if (purchaseProviderFactory == null)
            {
                throw new NotSupportedException("Sender country has no purchase provider");
            }

            var cart = new ShoppingCart(order, purchaseProviderFactory);

            var shippingLabel = cart.Finalize();

            Console.WriteLine(shippingLabel);
        }
        static void Main(string[] args)
        {
            #region Create Order
            Console.Write("Recipient Country: ");
            var recipientCountry = Console.ReadLine().Trim();

            Console.Write("Sender Country: ");
            var senderCountry = Console.ReadLine().Trim();

            Console.Write("Total Order Weight: ");
            var totalWeight = Convert.ToInt32(Console.ReadLine().Trim());

            var order = new Order
            {
                Recipient = new Address
                {
                    To      = "Tom Randles",
                    Country = recipientCountry
                },

                Sender = new Address
                {
                    To      = "Someone else",
                    Country = senderCountry
                },

                TotalWeight = totalWeight
            };

            order.LineItems.Add(new Item("CSHARP In Depth", "C# In Depth", 100m), 1);
            order.LineItems.Add(new Item("CONSULTING", "Building a website", 100m), 1);
            #endregion

            // Shopping cart and shipping provider now decoupled - loose coupling
            // The particular concrete factory to use should be based on some user input or configuration at runtime
            // var cart = new ShoppingCart(order, new GlobalShippingProviderFactory());

            // New implementation using the Abstract Factory pattern

            IPurchaseProviderFactory purchaseProviderFactory;



            // Benefit of Factory Provider - simply extend the code with new country specific
            // purchase provider factories and they will automatically be picked up - no interference
            // with other coding

            var factoryProvider = new PurchaseProviderFactoryProvider();
            purchaseProviderFactory = factoryProvider.CreateFactoryFor(order.Sender.Country);

            if (purchaseProviderFactory == null)
            {
                throw new NotSupportedException("Provider for country not found");
            }

            // Code no longer required - use Factory provider instead
            //if (order.Sender.Country == "Sweden")
            //{
            //    purchaseProviderFactory = new SwedishPurchaseProviderFactory();
            //}
            //else if (order.Sender.Country == "Australia")
            //{
            //    purchaseProviderFactory = new AustraliaPurchaseProviderFactory();
            //}
            //else
            //    throw new Exception("Sender country not supported");

            var cart          = new ShoppingCart(order, purchaseProviderFactory);
            var shippingLabel = cart.Finalize();

            Console.WriteLine(shippingLabel);
        }
        static void Main(string[] args)
        {
            Sender sender;
            Order  order;
            string shippingLabel;

            // Simple Factory (1)
            Console.WriteLine("Simple Factory start");
            sender = new Sender()
            {
                Country = Country.Germany
            };
            order = new Order(sender);
            AbstractFactoryPattern.SimpleFactory.ShoppingCart cart = new AbstractFactoryPattern.SimpleFactory.ShoppingCart(order);
            shippingLabel = cart.FinalizeOrder();
            Console.WriteLine(shippingLabel);
            Console.WriteLine("Simple Factory end");

            Console.WriteLine("-----------------------------------------------");

            // Factory Method (2)
            Console.WriteLine("Factory Method start");
            sender = new Sender()
            {
                Country = Country.Global
            };
            order = new Order(sender);

            // pass the suitable factory to the shopping cart based on certain configurations
            // for example, a vip user gets a FreeShippingProviderFactory
            AbstractFactoryPattern.FactoryMethod.Factories.GlobalShippingProviderFactory globalShippingProviderFactory = new AbstractFactoryPattern.FactoryMethod.Factories.GlobalShippingProviderFactory();

            // Benefit: the shopping cart is now completely decoupled from the creation of the shipping provider
            AbstractFactoryPattern.FactoryMethod.ShoppingCart cart2 = new AbstractFactoryPattern.FactoryMethod.ShoppingCart(order, globalShippingProviderFactory);
            shippingLabel = cart2.FinalizeOrder();
            Console.WriteLine(shippingLabel);
            Console.WriteLine("Factory Method end");

            Console.WriteLine("-----------------------------------------------");

            // Abstract Factory (3)
            // Is used in cases, where we want to group individual factories that have a common theme
            // hier wirds verwirrend...
            Console.WriteLine("Abstract Factory start");
            sender = new Sender()
            {
                Country = Country.Germany
            };
            order = new Order(sender)
            {
                Price = 120
            };

            // Factory Provider
            IPurchaseProviderFactory purchaseProviderFactory;
            var factoryProvider = new PurchaseProviderFactoryProvider();

            purchaseProviderFactory = factoryProvider.CreateFactoryFor(order.Sender.Country);

            AbstractFactoryPattern.AbstractFactory.ShoppingCart cart3 = new AbstractFactoryPattern.AbstractFactory.ShoppingCart(order, purchaseProviderFactory);
            shippingLabel = cart3.FinalizeOrder();
            Console.WriteLine(shippingLabel);

            Console.WriteLine("Abstract Factory end");

            Console.WriteLine("-----------------------------------------------");
        }