工厂与抽象工厂
本篇文章代码:https://gitee.com/bithachi_admin_admin/mycode/tree/master/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/factory
一、工厂模式
1. 什么是工厂模式?
- 工厂模式(Factory Pattern)提供了一种创建对象的最佳方式,是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式。
- 在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
**意图:**定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。(依赖倒置原则)
**主要解决:**主要解决接口选择的问题。
**何时使用:**我们明确地计划不同条件下创建不同实例时。
**如何解决:**让其子类实现工厂接口,返回的也是一个抽象的产品。
**关键代码:**创建过程在其子类执行。
应用实例:
- 您需要一辆汽车,可以直接从工厂里面提货,而不用去管这辆汽车是怎么做出来的,以及这个汽车里面的具体实现。
- Mybatis换数据库只需换方言和驱动就可以。
优点:
- 一个调用者想创建一个对象,只要知道其名称就可以了。
- 扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。
- 屏蔽产品的具体实现,调用者只关心产品的接口。
**缺点:**每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。
使用场景:
- 日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。
- 数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。
- 设计一个连接服务器的框架,需要三个协议,“POP3”、“IMAP”、“HTTP”,可以把这三个作为产品类,共同实现一个接口。
**注意事项:**作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。

2. 加盟披萨店案例
案例描述:你有一家披萨店,经营有成,击败了许多的竞争者,现在你想开扩大市场,建立加盟店。因为区域的差异,每家加盟店都可能想要提供不同风味的比萨(比方说纽约、芝加哥、加州),这受到了开店地点及该地区比萨美食家口味的影响。那么如何设计呢?
下面是案例的UML模型设计图:

PizzaStore:
public abstract class PizzaStore {abstract Pizza createPizza(String item);public Pizza orderPizza(String type) {Pizza pizza = createPizza(type);System.out.println("--- Making a " + pizza.getName() + " ---");pizza.prepare();pizza.bake();pizza.cut();pizza.box();return pizza;}
}
NYPizzaStore:
public class NYPizzaStore extends PizzaStore {@OverridePizza createPizza(String item) {if (item.equals("cheese")) {return new NYStyleCheesePizza();} else if (item.equals("veggie")) {return new NYStyleVeggiePizza();} else if (item.equals("clam")) {return new NYStyleClamPizza();} else if (item.equals("pepperoni")) {return new NYStylePepperoniPizza();} else {return null;}}
}
Pizza:
import java.util.ArrayList;
public abstract class Pizza {String name;String dough;String sauce;ArrayList<String> toppings = new ArrayList<String>();void prepare() {System.out.println("Prepare " + name);System.out.println("Tossing dough...");System.out.println("Adding sauce...");System.out.println("Adding toppings: ");for (String topping : toppings) {System.out.println(" " + topping);}}void bake() {System.out.println("Bake for 25 minutes at 350");}void cut() {System.out.println("Cut the pizza into diagonal slices");}void box() {System.out.println("Place pizza in official PizzaStore box");}public String getName() {return name;}@Overridepublic String toString() {StringBuffer display = new StringBuffer();display.append("---- " + name + " ----\n");display.append(dough + "\n");display.append(sauce + "\n");for (String topping : toppings) {display.append(topping + "\n");}return display.toString();}
}
NYStyleCheesePizza**:**
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 PizzaTestDrive {public static void main(String[] args) {PizzaStore nyStore = new NYPizzaStore();PizzaStore chicagoStore = new ChicagoPizzaStore();Pizza pizza = nyStore.orderPizza("cheese");System.out.println("Ethan ordered a " + pizza.getName() + "\n");pizza = chicagoStore.orderPizza("cheese");System.out.println("Joel ordered a " + pizza.getName() + "\n");pizza = nyStore.orderPizza("clam");System.out.println("Ethan ordered a " + pizza.getName() + "\n");pizza = chicagoStore.orderPizza("clam");System.out.println("Joel ordered a " + pizza.getName() + "\n");pizza = nyStore.orderPizza("pepperoni");System.out.println("Ethan ordered a " + pizza.getName() + "\n");pizza = chicagoStore.orderPizza("pepperoni");System.out.println("Joel ordered a " + pizza.getName() + "\n");pizza = nyStore.orderPizza("veggie");System.out.println("Ethan ordered a " + pizza.getName() + "\n");pizza = chicagoStore.orderPizza("veggie");System.out.println("Joel ordered a " + pizza.getName() + "\n");}
}
运行结果:
--- Making a NY Style Sauce and Cheese Pizza ---
Prepare NY Style Sauce and Cheese Pizza
Tossing dough...
Adding sauce...
Adding toppings: Grated Reggiano Cheese
Bake for 25 minutes at 350
Cut the pizza into diagonal slices
Place pizza in official PizzaStore box
Ethan ordered a NY Style Sauce and Cheese Pizza--- Making a Chicago Style Deep Dish Cheese Pizza ---
Prepare Chicago Style Deep Dish Cheese Pizza
Tossing dough...
Adding sauce...
Adding toppings: Shredded Mozzarella Cheese
Bake for 25 minutes at 350
Cutting the pizza into square slices
Place pizza in official PizzaStore box
Joel ordered a Chicago Style Deep Dish Cheese Pizza--- Making a NY Style Clam Pizza ---
Prepare NY Style Clam Pizza
Tossing dough...
Adding sauce...
Adding toppings: Grated Reggiano CheeseFresh Clams from Long Island Sound
Bake for 25 minutes at 350
Cut the pizza into diagonal slices
Place pizza in official PizzaStore box
Ethan ordered a NY Style Clam Pizza--- Making a Chicago Style Clam Pizza ---
Prepare Chicago Style Clam Pizza
Tossing dough...
Adding sauce...
Adding toppings: Shredded Mozzarella CheeseFrozen Clams from Chesapeake Bay
Bake for 25 minutes at 350
Cutting the pizza into square slices
Place pizza in official PizzaStore box
Joel ordered a Chicago Style Clam Pizza--- Making a NY Style Pepperoni Pizza ---
Prepare NY Style Pepperoni Pizza
Tossing dough...
Adding sauce...
Adding toppings: Grated Reggiano CheeseSliced PepperoniGarlicOnionMushroomsRed Pepper
Bake for 25 minutes at 350
Cut the pizza into diagonal slices
Place pizza in official PizzaStore box
Ethan ordered a NY Style Pepperoni Pizza--- Making a Chicago Style Pepperoni Pizza ---
Prepare Chicago Style Pepperoni Pizza
Tossing dough...
Adding sauce...
Adding toppings: Shredded Mozzarella CheeseBlack OlivesSpinachEggplantSliced Pepperoni
Bake for 25 minutes at 350
Cutting the pizza into square slices
Place pizza in official PizzaStore box
Joel ordered a Chicago Style Pepperoni Pizza--- Making a NY Style Veggie Pizza ---
Prepare NY Style Veggie Pizza
Tossing dough...
Adding sauce...
Adding toppings: Grated Reggiano CheeseGarlicOnionMushroomsRed Pepper
Bake for 25 minutes at 350
Cut the pizza into diagonal slices
Place pizza in official PizzaStore box
Ethan ordered a NY Style Veggie Pizza--- Making a Chicago Deep Dish Veggie Pizza ---
Prepare Chicago Deep Dish Veggie Pizza
Tossing dough...
Adding sauce...
Adding toppings: Shredded Mozzarella CheeseBlack OlivesSpinachEggplant
Bake for 25 minutes at 350
Cutting the pizza into square slices
Place pizza in official PizzaStore box
Joel ordered a Chicago Deep Dish Veggie Pizza进程已结束,退出代码0
二、抽象工程模式
1. 什么是抽象工厂模式?
- 抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂为其他工厂的父工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
- 在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。
**意图:**提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
**主要解决:**主要解决接口选择的问题。
**何时使用:**系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。
**如何解决:**在一个产品族里面,定义多个产品。
**关键代码:**在一个工厂里聚合多个同类产品。
**应用实例:**工作了,为了参加一些聚会,肯定有两套或多套衣服吧,比如说有商务装(成套,一系列具体产品)、时尚装(成套,一系列具体产品),甚至对于一个家庭来说,可能有商务女装、商务男装、时尚女装、时尚男装,这些也都是成套的,即一系列具体产品。假设一种情况,在您的家中,某一个衣柜(具体工厂)只能存放某一种这样的衣服(成套,一系列具体产品),每次拿这种成套的衣服时也自然要从这个衣柜中取出了。用 OOP 的思想去理解,所有的衣柜(具体工厂)都是衣柜类的(抽象工厂)某一个,而每一件成套的衣服又包括具体的上衣(某一具体产品),裤子(某一具体产品),这些具体的上衣其实也都是上衣(抽象产品),具体的裤子也都是裤子(另一个抽象产品)。
**优点:**当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
**缺点:**产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的 Creator 里加代码,又要在具体的里面加代码。
使用场景: 1、QQ 换皮肤,一整套一起换。 2、生成不同操作系统的程序。
**注意事项:**产品族难扩展,产品等级易扩展。

2. 给加盟披萨店新增原料工厂
案例描述:你有一家披萨店,经营有成,击败了许多的竞争者,现在你想开扩大市场,建立加盟店。因为区域的差异,每家加盟店都可能想要提供不同风味的比萨(比方说纽约、芝加哥、加州),这受到了开店地点及该地区比萨美食家口味的影响。那么如何设计呢?这是我们工厂模式的案例,现在我们在此案例上加点东西,我们希望所有的加盟店都使用统一的调料(原料):面团、酱料、腊肠、芝士、蔬菜、肉等。我们可以建造原料工厂来满足这种需求。

下面是UML设计模型:

下面给出核心实现代码;
**
**
披萨抽象类Pizza:
public abstract class Pizza {String name;Dough dough;Sauce sauce;Veggies veggies[];Cheese cheese;Pepperoni pepperoni;Clams clam;abstract void prepare();void bake() {System.out.println("Bake for 25 minutes at 350");}void cut() {System.out.println("Cutting the pizza into diagonal slices");}void box() {System.out.println("Place pizza in official PizzaStore box");}void setName(String name) {this.name = name;}String getName() {return name;}@Overridepublic String toString() {StringBuffer result = new StringBuffer();result.append("---- " + name + " ----\n");if (dough != null) {result.append(dough);result.append("\n");}if (sauce != null) {result.append(sauce);result.append("\n");}if (cheese != null) {result.append(cheese);result.append("\n");}if (veggies != null) {for (int i = 0; i < veggies.length; i++) {result.append(veggies[i]);if (i < veggies.length-1) {result.append(", ");}}result.append("\n");}if (clam != null) {result.append(clam);result.append("\n");}if (pepperoni != null) {result.append(pepperoni);result.append("\n");}return result.toString();}
}
具体的某种披萨类CheesePizza:
public class CheesePizza extends Pizza {//原料工厂PizzaIngredientFactory ingredientFactory;public CheesePizza(PizzaIngredientFactory ingredientFactory) {this.ingredientFactory = ingredientFactory;}@Overridevoid prepare() {System.out.println("Preparing " + name);dough = ingredientFactory.createDough();sauce = ingredientFactory.createSauce();cheese = ingredientFactory.createCheese();}
}
披萨店抽象类PizzaStore:
public abstract class PizzaStore {protected abstract Pizza createPizza(String item);public Pizza orderPizza(String type) {Pizza pizza = createPizza(type);System.out.println("--- Making a " + pizza.getName() + " ---");pizza.prepare();pizza.bake();pizza.cut();pizza.box();return pizza;}
}
纽约披萨店NYPizzaStore:
**
**
public class NYPizzaStore extends PizzaStore {@Overrideprotected Pizza createPizza(String item) {Pizza pizza = null;PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();if (item.equals("cheese")) {pizza = new CheesePizza(ingredientFactory);pizza.setName("New York Style Cheese Pizza");} else if (item.equals("veggie")) {pizza = new VeggiePizza(ingredientFactory);pizza.setName("New York Style Veggie Pizza");} else if (item.equals("clam")) {pizza = new ClamPizza(ingredientFactory);pizza.setName("New York Style Clam Pizza");} else if (item.equals("pepperoni")) {pizza = new PepperoniPizza(ingredientFactory);pizza.setName("New York Style Pepperoni Pizza");} return pizza;}
}
原料工厂抽象类****PizzaIngredientFactory:
public interface PizzaIngredientFactory {public Dough createDough();public Sauce createSauce();public Cheese createCheese();public Veggies[] createVeggies();public Pepperoni createPepperoni();public Clams createClam();
}
具体的纽约原料工厂****NYPizzaIngredientFactory:
public class NYPizzaIngredientFactory implements PizzaIngredientFactory {@Overridepublic Dough createDough() {return new ThinCrustDough();}@Overridepublic Sauce createSauce() {return new MarinaraSauce();}@Overridepublic Cheese createCheese() {return new ReggianoCheese();}@Overridepublic Veggies[] createVeggies() {Veggies veggies[] = { new Garlic(), new Onion(), new Mushroom(), new RedPepper() };return veggies;}@Overridepublic Pepperoni createPepperoni() {return new SlicedPepperoni();}@Overridepublic Clams createClam() {return new FreshClams();}
}
某类型的具体原料产品****Mushroom:
public class Mushroom implements Veggies {@Overridepublic String toString() {return "Mushrooms";}
}
测试运行PizzaTestDrive:
public class PizzaTestDrive {public static void main(String[] args) {PizzaStore nyStore = new NYPizzaStore();PizzaStore chicagoStore = new ChicagoPizzaStore();Pizza pizza = nyStore.orderPizza("cheese");System.out.println("Ethan ordered a " + pizza + "\n");pizza = chicagoStore.orderPizza("cheese");System.out.println("Joel ordered a " + pizza + "\n");pizza = nyStore.orderPizza("clam");System.out.println("Ethan ordered a " + pizza + "\n");pizza = chicagoStore.orderPizza("clam");System.out.println("Joel ordered a " + pizza + "\n");pizza = nyStore.orderPizza("pepperoni");System.out.println("Ethan ordered a " + pizza + "\n");pizza = chicagoStore.orderPizza("pepperoni");System.out.println("Joel ordered a " + pizza + "\n");pizza = nyStore.orderPizza("veggie");System.out.println("Ethan ordered a " + pizza + "\n");pizza = chicagoStore.orderPizza("veggie");System.out.println("Joel ordered a " + pizza + "\n");}
}
运行结果:
--- Making a New York Style Cheese Pizza ---
Preparing New York Style Cheese Pizza
Bake for 25 minutes at 350
Cutting the pizza into diagonal slices
Place pizza in official PizzaStore box
Ethan ordered a ---- New York Style Cheese Pizza ----
Thin Crust Dough
Marinara Sauce
Reggiano Cheese--- Making a Chicago Style Cheese Pizza ---
Preparing Chicago Style Cheese Pizza
Bake for 25 minutes at 350
Cutting the pizza into diagonal slices
Place pizza in official PizzaStore box
Joel ordered a ---- Chicago Style Cheese Pizza ----
ThickCrust style extra thick crust dough
Tomato sauce with plum tomatoes
Shredded Mozzarella--- Making a New York Style Clam Pizza ---
Preparing New York Style Clam Pizza
Bake for 25 minutes at 350
Cutting the pizza into diagonal slices
Place pizza in official PizzaStore box
Ethan ordered a ---- New York Style Clam Pizza ----
Thin Crust Dough
Marinara Sauce
Reggiano Cheese
Fresh Clams from Long Island Sound--- Making a Chicago Style Clam Pizza ---
Preparing Chicago Style Clam Pizza
Bake for 25 minutes at 350
Cutting the pizza into diagonal slices
Place pizza in official PizzaStore box
Joel ordered a ---- Chicago Style Clam Pizza ----
ThickCrust style extra thick crust dough
Tomato sauce with plum tomatoes
Shredded Mozzarella
Frozen Clams from Chesapeake Bay--- Making a New York Style Pepperoni Pizza ---
Preparing New York Style Pepperoni Pizza
Bake for 25 minutes at 350
Cutting the pizza into diagonal slices
Place pizza in official PizzaStore box
Ethan ordered a ---- New York Style Pepperoni Pizza ----
Thin Crust Dough
Marinara Sauce
Reggiano Cheese
Garlic, Onion, Mushrooms, Red Pepper
Sliced Pepperoni--- Making a Chicago Style Pepperoni Pizza ---
Preparing Chicago Style Pepperoni Pizza
Bake for 25 minutes at 350
Cutting the pizza into diagonal slices
Place pizza in official PizzaStore box
Joel ordered a ---- Chicago Style Pepperoni Pizza ----
ThickCrust style extra thick crust dough
Tomato sauce with plum tomatoes
Shredded Mozzarella
Black Olives, Spinach, Eggplant
Sliced Pepperoni--- Making a New York Style Veggie Pizza ---
Preparing New York Style Veggie Pizza
Bake for 25 minutes at 350
Cutting the pizza into diagonal slices
Place pizza in official PizzaStore box
Ethan ordered a ---- New York Style Veggie Pizza ----
Thin Crust Dough
Marinara Sauce
Reggiano Cheese
Garlic, Onion, Mushrooms, Red Pepper--- Making a Chicago Style Veggie Pizza ---
Preparing Chicago Style Veggie Pizza
Bake for 25 minutes at 350
Cutting the pizza into diagonal slices
Place pizza in official PizzaStore box
Joel ordered a ---- Chicago Style Veggie Pizza ----
ThickCrust style extra thick crust dough
Tomato sauce with plum tomatoes
Shredded Mozzarella
Black Olives, Spinach, Eggplant进程已结束,退出代码0
三、比较工厂模式与抽象工厂模式

- 工厂方法使用继承: 把对象的创建委托给子类,子类实现工厂方法来创建对象。
- 抽象工厂使用对象组合(在): 对象的创建被实现在工厂接口所暴露出来的方法中。

本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
