Design Patterns article
The mediator pattern
The proxy pattern
Abstract Factory Pattern details – Head First design pattern
Decorator pattern
Adapter mode
The strategy pattern
Observer model
Builder Mode
Project instance
Suppose you have a pizza shop, and you have many varieties of pizzas, and you want to display all of your pizza varieties in the system. It is not difficult to implement this functionality in the normal way:
Public class PizzaStore {Pizza orderPizza(String type) {Pizza Pizza = null; If (type.equals("cheese")) {pizza = new CheesePizza(); } else if (type. Equals ("clam")) {pizza = new ClamPizza(); } else if (type.equals("veggie")) {VeggiePizza = new VeggiePizza(); } pizza. Prepare (); Pizza. Bake (); Pizza. The cut (); Pizza box (); Return pizza; }}Copy the code
In this way, the selection of pizza and the production process are all put together. If a new pizza is launched, the OrderPizza method should be modified, which does not conform to the opening and closing principle.
We can move this code into a special class that creates Pizza. We will call the objects of this class “factories”.
Simple Factory
According to the rule of “separate and encapsulate the changes”, we can remove the pizza instance creation area from this area, because it may be followed by some other pizza types, and an object will create the pizza object exclusively. If there is a SimplePizzaFactory, orderPizza() becomes the customer of this object;
When pizzaStore calls orderPizza(), it asks the pizza factory to make one. OrderPizza () only cares about getting one pizza from the factory;
public class SimplePizzaFactory { public PizzaCreatePizza(string pizzaType){ Pizza pizza = null; if(pizzaType.Equals("cheese")) pizza = newCheesePizza(); else if (pizzaType.Equals("pepperoni")) pizza = newPepperoniPizza(); else if(pizzaType.Equals("clam")) pizza = newCalmPizza(); else if(pizzaType.Equals("veggie")) pizza = newVeggiePizza(); return pizza; }}Copy the code
Next, the Pizza category:
public class Pizza { Pizza OrderPizza(stringpizzaType){ Pizza pizza; SimplePizzaFactory simplePizzaFactory = new SimplePizzaFactory(); / / generated pizza pizza. = simplePizzaFactory CreatePizza (pizzaType); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; }}Copy the code
In this way, you can follow the principle of abstracting the changing parts into a class. The next time you need a change, you just need to make changes to the part of the changed class.
The UML diagram is shown below.
The purpose of the simple factory is to realize the details of the production object and produce according to the order. Each store has its own factory. Here, OrderPizza can be a customer of the factory, and of course other similar methods, such as PizzaShopMenu, can also be a customer of the factory. The customer is there to get the factory-generated objects. The former is to sell to people, and the latter is to use the Pizza class to get its description and price, etc. This follows the principle of finding the changing parts and encapsulating them in a class to achieve reuse.
The simple factory is simple because it produces a given Pizza only on demand.
Features: All products are produced in one factory.
The simple factory above is not a true pattern, just a programming habit. It is not a factory pattern, but it is a basic requirement.
Let’s look at the implementation of the factory method.
The factory method
Background update:
If you’re going to open a store now and all the franchisees come in and they’re going to develop pizzas for local tastes, you’ll need a factory in each location. That means each location inherits the SimpleFactory class, but each factory isn’t exactly using your original baking method. Perhaps, we can make use of simple factories as shown in 1 to create different factories corresponding to franchise stores in different regions.
Another problem caused by this is that different franchise restaurants may have different pizza production processes and methods. How to keep the franchise and the creation of pizza together while maintaining a certain degree of flexibility?
We could put the CreatePizza () method back into PizzaStore, but make it abstract, and then create a subclass of PizzaStore for each regional franchise.
As follows:
The corresponding code is as follows:
public abstract class PizzaStore { public PizzaOrderPizza(string pizzaType) { Pizza pizza =CreatePizza(pizzaType); pizza.Prepare(); pizza.Bake(); pizza.Cut(); pizza.Box(); return pizza; } public abstract Pizza CreatePizza(string pizzaType); // Move the factory object into this method, which is abstract}Copy the code
Codes corresponding to the two branches:
Public class NYPizzaStore extends PizzaStore {@override protected Pizza createPizza(String type) {if (type.equals("cheese")) {return new NYCheesePizza(); } return null; } } public class ChicagoPizzaStore extends PizzaStore { @Override protected Pizza createPizza(String type) { if (type.equals("cheese")) {return new ChicagoCheesePizza(); } return null; }}Copy the code
We need to create a Pizza entity class:
public abstract class Pizza { String name; // Name String dough; String sauce; ArrayList<String> toppings = new ArrayList<String>(); Void prepare() {system.out.println (" prepare "+ name); System.out.println(" knead the dough... ); System.out.println(" add sauce...") ); System.out.println(" add padding: "); for (int i = 0; i < toppings.size(); i++) { System.out.println(" " + toppings.get(i)); }} void bake() {system.out.println (" bake for 25 minutes "); } void cut() {system.out.println (" slice Pizza diagonal "); } void box() {system.out.println (); } public String getName() { return name; }}Copy the code
Then we need some specific subcategories. Let’s define two subcategories: New York style CheesePizza and Chicago style cheese pizza.
public class NYStyleCheesePizza extends Pizza { public NYStyleCheesePizza() { name = "NY Style Sauce and Cheese Pizza"; dough = "Thin Crust Dough"; sauce = "Marinara Sauce"; toppings.add("Grated Reggiano Cheese"); } } public class ChicagoStyleCheesePizza extends Pizza { public ChicagoStyleCheesePizza() { name = "Chicago Style Deep Dish Cheese Pizza"; dough = "Extra Thick Crust Dough"; sauce = "Plum Tomato Sauce"; toppings.add("Shredded Mozzarella Cheese"); } // Can override cut() method void cut() {system.out.println ("Cutting the pizza into square slices"); }}Copy the code
2.2 summarize
All factory patterns encapsulate object creation, and the factory method pattern encapsulates the object creation process by letting subclasses decide what objects should be created.
The factory method pattern defines an interface for creating objects, but it is up to the subclass to decide which class to instantiate. The factory method lets the class defer instantiation to the subclass.
Creator class
Product class
The difference between a simple factory and a factory approach?
A simple factory does everything in one place, whereas a factory method creates a framework and lets subclasses decide how to implement it. A simple factory approach can encapsulate object creation, but it does not have the flexibility of a factory approach because a simple factory cannot change the product being created.
The abstract factory
Creating a Factory Interface
Back to the Pizza store above, now there is a new demand to ensure that each franchise store uses high-quality materials. We plan to set up a processing plant to produce raw materials and send them to each franchise store. This factory is responsible for creating each ingredient in the family of ingredients. The factory needs to produce doughs, sauces, cheeses, etc. Define an interface for the factory that is responsible for all raw materials:
public interface PizzaIngredientFactory {
Dough CreateDough();
Sauce CreateSauce();
Cheese CreateCheese();
Veggies[] CreateVeggies();
Pepperoni CreatePepperoni();
Clams CreateClam();
}
Copy the code
Create a raw material factory
Public class ingredientFactory extends PizzaIngredientFactory {public Dough CreateDough() { return new ThinCrustDough(); } public Sauce CreateSauce() { return new MarinaraSauce(); } public Cheese CreateCheese() { return new ReggianoCheese(); } public Veggies[] CreateVeggies() { Veggies[] veggies = new Veggies[]{ new Garlic(), new Onion(), new Mushroom(), new RedPepper() }; return veggies; } public Pepperoni CreatePepperoni() { return new SlicedPepperoni(); } public Clams CreateClam() { return new FreshClams(); }}Copy the code
Re-abstract the Pizza class
public abstract class Pizza { public string name; public Dough dough; public Sauce sauce; public Veggies[] veggies; public Cheese cheese; public Pepperoni pepperoni; public Clams clam; public ArrayList toppings = newArrayList(); public abstract void Prepare(); // Declare the Prepare () method abstract. In this method, we need to collect the raw materials for Pizza from the factory. public void Bake() { System.Console.WriteLine("Bakefor 25 minutes at 350"); } public void Cut() { System.Console.WriteLine("Cuttingthe pizza into diagonal slices"); } public void Box() { System.Console.WriteLine("Placepizza in official PizzaStore box"); } public string GetName() { return name; }}Copy the code
Re-implement Pizza
public class NYStyleCheesePizza extends Pizza { PizzaIngredientFactory ingredientFactory; Public NYStyleCheesePizza (PizzaIngredientFactoryingredientFactory) {/ / plant to provide raw materials needed to make Pizza, so every Pizza class needs from a factory in the constructor, IngredientFactory =ingredientFactory; name = "NY StyleSauc and Cheese Pizza"; toppings.Add("GratedReggiano Cheese"); } public override void Prepare() { System.Console.WriteLine("Preparing" + name); dough = ingredientFactory.CreateDough(); sauce = ingredientFactory.CreateSauce(); cheese = ingredientFactory.CreateCheese(); }}Copy the code
Re-produce pizza
public class MYPizzaStore extends PizzaStore { public override Pizza CreatePizza(string type) { Pizza pizza=null; PizzaIngredientFactory ingredientFactory= new NYPizzaIngredientFactory(); switch(type) { case "cheese": pizza = new NYStyleCheesePizza(ingredientFactory); break; case "veggie": pizza=new NYStyleVeggiePizza(ingredientFactory); break; case "clam": pizza=new NYStyleClamPizza(ingredientFactory); break; case "pepperoni": pizza=new NYStylePepperoniPizza(ingredientFactory); break; } return pizza; }}Copy the code
Through this series of operations, we introduced a new type of factory, namely the so-called “abstract factory”, to create the original Pizza family. By abstracting the interface provided by the factory to create a product family and writing code using this interface, our code will be decoupled from the actual factory to implement a variety of factories in different contexts and produce a variety of products.
Define the abstract factory schema
The Abstract factory pattern provides an interface for creating families of related or dependent objects without the need for deadly concrete classes.
The abstract factory pattern allows customers to use abstract interfaces to create a set of related products, from which they are decoupled without knowing what the actual product is.
Abstract factory vs. factory method
Both the abstract factory and the factory method are responsible for creating objects.
Abstract factories are through combinations of objects
Defines an interface for creating objects, but since subclasses decide which class to instantiate, the factory method lets the class defer instantiation to subclasses.
So when you create an object using factory methods, you extend a class and override its factory methods.
The whole factory method pattern is simply to create objects by subclassing them. In this way, customers only need to know the abstract type they are using, and the subclass is responsible for determining the concrete type. Decouple customers from concrete types.
The factory method is inheritance.
The abstract factory approach is a collection of related products used to create families of related or dependent objects without explicitly specifying concrete classes.
Refer to the article
Blog.csdn.net/xuemoyao/ar…
www.cnblogs.com/lzhp/p/3375…