namespace Ch4PizzaStore; public abstract class Pizza(string name, string dough, string sauce, List toppings) { public string Name { get; } = name; internal void Prepare() { Console.WriteLine($"Preparing {Name}"); Console.WriteLine($"Tossing {dough} dough..."); Console.WriteLine($"Adding {sauce} sauce..."); Console.WriteLine("Adding toppings:"); foreach (var topping in toppings) { Console.WriteLine($"\t{topping}"); } } // While in Java all methods are by default `virtual`, C# is the same as C++, // all methods are final/selaed until explicitly marked as virtual. internal virtual void Bake() { Console.WriteLine("Bake for 25 minutes at 350"); } internal virtual void Cut() { Console.WriteLine("Cutting the pizza into diagonal slices"); } internal virtual void Box() { Console.WriteLine("Place pizza in official PizzaStore box"); } } public class NYStyleCheesePizza() : Pizza("NY Style Sauce and Cheese Pizza", "Thin Crust Dough", "Marinara Sauce", ["Grated Reggiano Cheese"]); public class ChicagoStyleCheesePizza() : Pizza("Chicago Style Deep Dish Cheese Pizza", "Extra Thick Crust Dough", "Plum Tomato Sauce", ["Shredded Mozzarella Cheese"]) { internal override void Cut() { Console.WriteLine("Cutting the pizza into square slices"); } } public abstract class PizzaStore { protected abstract Pizza CreatePizza(string type); public Pizza OrderPizza(string type) { var pizza = CreatePizza(type); pizza.Prepare(); pizza.Bake(); pizza.Cut(); pizza.Box(); return pizza; } } public class NYPizzaStore : PizzaStore { protected override Pizza CreatePizza(string type) { return type switch { "cheese" => new NYStyleCheesePizza(), _ => throw new ArgumentOutOfRangeException(nameof(type), type, null) }; } } public class ChicagoPizzaStore : PizzaStore { protected override Pizza CreatePizza(string type) { return type switch { "cheese" => new ChicagoStyleCheesePizza(), _ => throw new ArgumentOutOfRangeException(nameof(type), type, null) }; } }