Фабричный метод (Factory method)
Также известен как Виртуальный конструктор (Virtual constructor).
Паттерн Фабричный Метод определяет интерфейс создания объекта, но позволяет субклассам выбрать класс создаваемого экземпляра. Таким образом, Фабричный Метод делегирует операцию создания экземпляра субклассам.
-
Product - абстрактый продукт
-
ConcreteProduct - конкретный продукт
-
Creator - абстрактный создатель
-
ConcreteCreator - конкретный создатель
Абстрактная реализация на C# (GoF)
/// <summary>
/// MainApp startup class for Structural
/// Factory Method Design Pattern.
/// </summary>
internal class MainApp
{
/// <summary>
/// Entry point into console application.
/// </summary>
private static void Main()
{
// An array of creators
Creator[] creators = new Creator[2];
creators[0] = new ConcreteCreatorA();
creators[1] = new ConcreteCreatorB();
// Iterate over creators and create products
foreach (Creator creator in creators)
{
Product product = creator.FactoryMethod();
Console.WriteLine("Created {0}",
product.GetType().Name);
}
// Wait for user
Console.ReadKey();
}
}
/// <summary>
/// The 'Product' abstract class
/// </summary>
internal abstract class Product
{
}
/// <summary>
/// A 'ConcreteProduct' class
/// </summary>
internal class ConcreteProductA : Product
{
}
/// <summary>
/// A 'ConcreteProduct' class
/// </summary>
internal class ConcreteProductB : Product
{
}
/// <summary>
/// The 'Creator' abstract class
/// </summary>
internal abstract class Creator
{
public abstract Product FactoryMethod();
}
/// <summary>
/// A 'ConcreteCreator' class
/// </summary>
internal class ConcreteCreatorA : Creator
{
public override Product FactoryMethod()
{
return new ConcreteProductA();
}
}
/// <summary>
/// A 'ConcreteCreator' class
/// </summary>
internal class ConcreteCreatorB : Creator
{
public override Product FactoryMethod()
{
return new ConcreteProductB();
}
}
Реальная реализация на C# (GoF)
/// <summary>
/// MainApp startup class for Real-World
/// Factory Method Design Pattern.
/// </summary>
internal class MainApp
{
/// <summary>
/// Entry point into console application.
/// </summary>
private static void Main()
{
// Note: constructors call Factory Method
Document[] documents = new Document[2];
documents[0] = new Resume();
documents[1] = new Report();
// Display document pages
foreach (Document document in documents)
{
Console.WriteLine("\n" + document.GetType().Name + "--");
foreach (Page page in document.Pages)
{
Console.WriteLine(" " + page.GetType().Name);
}
}
// Wait for user
Console.ReadKey();
}
}
/// <summary>
/// The 'Product' abstract class
/// </summary>
internal abstract class Page
{
}
/// <summary>
/// A 'ConcreteProduct' class
/// </summary>
internal class SkillsPage : Page
{
}
/// <summary>
/// A 'ConcreteProduct' class
/// </summary>
internal class EducationPage : Page
{
}
/// <summary>
/// A 'ConcreteProduct' class
/// </summary>
internal class ExperiencePage : Page
{
}
/// <summary>
/// A 'ConcreteProduct' class
/// </summary>
internal class IntroductionPage : Page
{
}
/// <summary>
/// A 'ConcreteProduct' class
/// </summary>
internal class ResultsPage : Page
{
}
/// <summary>
/// A 'ConcreteProduct' class
/// </summary>
internal class ConclusionPage : Page
{
}
/// <summary>
/// A 'ConcreteProduct' class
/// </summary>
internal class SummaryPage : Page
{
}
/// <summary>
/// A 'ConcreteProduct' class
/// </summary>
internal class BibliographyPage : Page
{
}
/// <summary>
/// The 'Creator' abstract class
/// </summary>
internal abstract class Document
{
private List<Page> pages = new List<Page>();
// Constructor calls abstract Factory method
public Document()
{
this.CreatePages();
}
public List<Page> Pages
{
get { return pages; }
}
// Factory Method
public abstract void CreatePages();
}
/// <summary>
/// A 'ConcreteCreator' class
/// </summary>
internal class Resume : Document
{
// Factory Method implementation
public override void CreatePages()
{
Pages.Add(new SkillsPage());
Pages.Add(new EducationPage());
Pages.Add(new ExperiencePage());
}
}
/// <summary>
/// A 'ConcreteCreator' class
/// </summary>
internal class Report : Document
{
// Factory Method implementation
public override void CreatePages()
{
Pages.Add(new IntroductionPage());
Pages.Add(new ResultsPage());
Pages.Add(new ConclusionPage());
Pages.Add(new SummaryPage());
Pages.Add(new BibliographyPage());
}
}
Улучшенная реальная реализация на C# (GoF)
/// <summary>
/// MainApp startup class for .NET optimized
/// Factory Method Design Pattern.
/// </summary>
internal class MainApp
{
/// <summary>
/// Entry point into console application.
/// </summary>
private static void Main()
{
// Document constructors call Factory Method
var documents = new List<Document> { new Resume(), new Report() };
// Display document pages
foreach (var document in documents)
{
Console.WriteLine(document + "--");
foreach (var page in document.Pages)
{
Console.WriteLine(" " + page);
}
Console.WriteLine();
}
// Wait for user
Console.ReadKey();
}
}
/// <summary>
/// The 'Product' abstract class
/// </summary>
internal abstract class Page
{
// Override. Display class name
public override string ToString()
{
return this.GetType().Name;
}
}
/// <summary>
/// A 'ConcreteProduct' class
/// </summary>
internal class SkillsPage : Page
{
}
/// <summary>
/// A 'ConcreteProduct' class
/// </summary>
internal class EducationPage : Page
{
}
/// <summary>
/// A 'ConcreteProduct' class
/// </summary>
internal class ExperiencePage : Page
{
}
/// <summary>
/// A 'ConcreteProduct' class
/// </summary>
internal class IntroductionPage : Page
{
}
/// <summary>
/// A 'ConcreteProduct' class
/// </summary>
internal class ResultsPage : Page
{
}
/// <summary>
/// A 'ConcreteProduct' class
/// </summary>
internal class ConclusionPage : Page
{
}
/// <summary>
/// A 'ConcreteProduct' class
/// </summary>
internal class SummaryPage : Page
{
}
/// <summary>
/// A 'ConcreteProduct' class
/// </summary>
internal class BibliographyPage : Page
{
}
/// <summary>
/// The 'Creator' abstract class
/// </summary>
internal abstract class Document
{
// Constructor invokes Factory Method
public Document()
{
this.CreatePages();
}
// Gets list of document pages
public List<Page> Pages { get; protected set; }
// Factory Method
public abstract void CreatePages();
// Override
public override string ToString()
{
return this.GetType().Name;
}
}
/// <summary>
/// A 'ConcreteCreator' class
/// </summary>
internal class Resume : Document
{
// Factory Method implementation
public override void CreatePages()
{
Pages = new List<Page>
{ new SkillsPage(),
new EducationPage(),
new ExperiencePage() };
}
}
/// <summary>
/// A 'ConcreteCreator' class
/// </summary>
internal class Report : Document
{
// Factory Method implementation
public override void CreatePages()
{
Pages = new List<Page>
{ new IntroductionPage(),
new ResultsPage(),
new ConclusionPage(),
new SummaryPage(),
new BibliographyPage() };
}
}
Реализация на C# (Head First)
internal class PizzaTestDrive
{
private static void Main(string[] args)
{
PizzaStore nyStore = new NYPizzaStore();
PizzaStore chicagoStore = new ChicagoPizzaStore();
Pizza pizza = nyStore.OrderPizza("cheese");
Console.WriteLine("Ethan ordered a " + pizza.Name + "\n");
pizza = chicagoStore.OrderPizza("cheese");
Console.WriteLine("Joel ordered a " + pizza.Name + "\n");
pizza = nyStore.OrderPizza("clam");
Console.WriteLine("Ethan ordered a " + pizza.Name + "\n");
pizza = chicagoStore.OrderPizza("clam");
Console.WriteLine("Joel ordered a " + pizza.Name + "\n");
pizza = nyStore.OrderPizza("pepperoni");
Console.WriteLine("Ethan ordered a " + pizza.Name + "\n");
pizza = chicagoStore.OrderPizza("pepperoni");
Console.WriteLine("Joel ordered a " + pizza.Name + "\n");
pizza = nyStore.OrderPizza("veggie");
Console.WriteLine("Ethan ordered a " + pizza.Name + "\n");
pizza = chicagoStore.OrderPizza("veggie");
Console.WriteLine("Joel ordered a " + pizza.Name + "\n");
// Wait for user
Console.ReadKey();
}
}
#region Pizza Stores
public abstract class PizzaStore
{
public abstract Pizza CreatePizza(string item);
public Pizza OrderPizza(string type)
{
Pizza pizza = CreatePizza(type);
Console.WriteLine("--- Making a " + pizza.Name + " ---");
pizza.Prepare();
pizza.Bake();
pizza.Cut();
pizza.Box();
return pizza;
}
}
public class NYPizzaStore : PizzaStore
{
public override Pizza CreatePizza(String item)
{
Pizza pizza = null;
switch (item)
{
case "cheese":
pizza = new NYStyleCheesePizza();
break;
case "veggie":
pizza = new NYStyleVeggiePizza();
break;
case "clam":
pizza = new NYStyleClamPizza();
break;
case "pepperoni":
pizza = new NYStylePepperoniPizza();
break;
}
return pizza;
}
}
public class ChicagoPizzaStore : PizzaStore
{
public override Pizza CreatePizza(String item)
{
Pizza pizza = null;
switch (item)
{
case "cheese":
pizza = new ChicagoStyleCheesePizza();
break;
case "veggie":
pizza = new ChicagoStyleVeggiePizza();
break;
case "clam":
pizza = new ChicagoStyleClamPizza();
break;
case "pepperoni":
pizza = new ChicagoStylePepperoniPizza();
break;
}
return pizza;
}
}
// Alternatively use this store
public class DependentPizzaStore
{
public Pizza CreatePizza(string style, string type)
{
Pizza pizza = null;
if (style == "NY")
{
switch (type)
{
case "cheese":
pizza = new NYStyleCheesePizza();
break;
case "veggie":
pizza = new NYStyleVeggiePizza();
break;
case "clam":
pizza = new NYStyleClamPizza();
break;
case "pepperoni":
pizza = new NYStylePepperoniPizza();
break;
}
}
else if (style == "Chicago")
{
switch (type)
{
case "cheese":
pizza = new ChicagoStyleCheesePizza();
break;
case "veggie":
pizza = new ChicagoStyleVeggiePizza();
break;
case "clam":
pizza = new ChicagoStyleClamPizza();
break;
case "pepperoni":
pizza = new ChicagoStylePepperoniPizza();
break;
}
}
else
{
Console.WriteLine("Error: invalid store");
return null;
}
pizza.Prepare();
pizza.Bake();
pizza.Cut();
pizza.Box();
return pizza;
}
}
#endregion Pizza Stores
#region Pizzas
public abstract class Pizza
{
public Pizza()
{
Toppings = new List<string>();
}
public string Name { get; set; }
public string Dough { get; set; }
public string Sauce { get; set; }
public List<string> Toppings { get; set; }
public void Prepare()
{
Console.WriteLine("Preparing " + Name);
Console.WriteLine("Tossing dough...");
Console.WriteLine("Adding sauce...");
Console.WriteLine("Adding toppings: ");
foreach (string topping in Toppings)
{
Console.WriteLine(" " + topping);
}
}
public void Bake()
{
Console.WriteLine("Bake for 25 minutes at 350");
}
public virtual void Cut()
{
Console.WriteLine("Cutting the pizza into diagonal slices");
}
public void Box()
{
Console.WriteLine("Place pizza in official PizzaStore box");
}
public override string ToString()
{
StringBuilder display = new StringBuilder();
display.Append("---- " + Name + " ----\n");
display.Append(Dough + "\n");
display.Append(Sauce + "\n");
foreach (string topping in Toppings)
{
display.Append(topping.ToString() + "\n");
}
return display.ToString();
}
}
public class ChicagoStyleVeggiePizza : Pizza
{
public ChicagoStyleVeggiePizza()
{
Name = "Chicago Deep Dish Veggie Pizza";
Dough = "Extra Thick Crust Dough";
Sauce = "Plum Tomato Sauce";
Toppings.Add("Shredded Mozzarella Cheese");
Toppings.Add("Black Olives");
Toppings.Add("Spinach");
Toppings.Add("Eggplant");
}
public override void Cut()
{
Console.WriteLine("Cutting the pizza into square slices");
}
}
public class ChicagoStylePepperoniPizza : Pizza
{
public ChicagoStylePepperoniPizza()
{
Name = "Chicago Style Pepperoni Pizza";
Dough = "Extra Thick Crust Dough";
Sauce = "Plum Tomato Sauce";
Toppings.Add("Shredded Mozzarella Cheese");
Toppings.Add("Black Olives");
Toppings.Add("Spinach");
Toppings.Add("Eggplant");
Toppings.Add("Sliced Pepperoni");
}
public override void Cut()
{
Console.WriteLine("Cutting the pizza into square slices");
}
}
public class ChicagoStyleClamPizza : Pizza
{
public ChicagoStyleClamPizza()
{
Name = "Chicago Style Clam Pizza";
Dough = "Extra Thick Crust Dough";
Sauce = "Plum Tomato Sauce";
Toppings.Add("Shredded Mozzarella Cheese");
Toppings.Add("Frozen Clams from Chesapeake Bay");
}
public override void Cut()
{
Console.WriteLine("Cutting the pizza into square slices");
}
}
public class ChicagoStyleCheesePizza : Pizza
{
public ChicagoStyleCheesePizza()
{
Name = "Chicago Style Deep Dish Cheese Pizza";
Dough = "Extra Thick Crust Dough";
Sauce = "Plum Tomato Sauce";
Toppings.Add("Shredded Mozzarella Cheese");
}
public override void Cut()
{
Console.WriteLine("Cutting the pizza into square slices");
}
}
public class NYStyleVeggiePizza : Pizza
{
public NYStyleVeggiePizza()
{
Name = "NY Style Veggie Pizza";
Dough = "Thin Crust Dough";
Sauce = "Marinara Sauce";
Toppings.Add("Grated Reggiano Cheese");
Toppings.Add("Garlic");
Toppings.Add("Onion");
Toppings.Add("Mushrooms");
Toppings.Add("Red Pepper");
}
}
public class NYStylePepperoniPizza : Pizza
{
public NYStylePepperoniPizza()
{
Name = "NY Style Pepperoni Pizza";
Dough = "Thin Crust Dough";
Sauce = "Marinara Sauce";
Toppings.Add("Grated Reggiano Cheese");
Toppings.Add("Sliced Pepperoni");
Toppings.Add("Garlic");
Toppings.Add("Onion");
Toppings.Add("Mushrooms");
Toppings.Add("Red Pepper");
}
}
public class NYStyleClamPizza : Pizza
{
public NYStyleClamPizza()
{
Name = "NY Style Clam Pizza";
Dough = "Thin Crust Dough";
Sauce = "Marinara Sauce";
Toppings.Add("Grated Reggiano Cheese");
Toppings.Add("Fresh Clams from Long Island Sound");
}
}
public class NYStyleCheesePizza : Pizza
{
public NYStyleCheesePizza()
{
Name = "NY Style Sauce and Cheese Pizza";
Dough = "Thin Crust Dough";
Sauce = "Marinara Sauce";
Toppings.Add("Grated Reggiano Cheese");
}
}
#endregion Pizzas
Реализация на JAVA
TODO