正文
一、定義
工廠方法模式定義了一個創建對象的接口,但由子類決定要實例化的類是哪一個。工廠方法讓類把實例化推遲到子類。
PS:在設計模式中,“實現一個接口”泛指實現某個超類型(可以是類或接口)的某個方法。
要點:
- 通過子類來創建具體的對象。客戶只需要知道他們所使用的抽象類型即可。
- 由子類決定要實例化的類是哪一個,是指在編寫創建者類時,不需要知道實際創建的產品是哪一個。選擇了使用哪個創建者子類,自然就決定了實際創建的產品是什麼。
- 對象統一由定義好的工廠方法來創建。
二、實現步驟
1、創建產品抽象類
/**
* 產品抽象類
*/
public abstract class Product {
String name;
public String getName() {
return name;
}
}
2、創建具體的產品,並繼承產品抽象類
(1)產品A1
/**
* 產品A1
*/
public class ConcreteProductA1 extends Product {
public ConcreteProductA1() {
name = "ConcreteProductA1";
}
}
(2)產品A2
/**
* 產品A2
*/
public class ConcreteProductA2 extends Product {
public ConcreteProductA2() {
name = "ConcreteProductA2";
}
}
(3)產品B1
/**
* 產品B1
*/
public class ConcreteProductB1 extends Product {
public ConcreteProductB1() {
name = "ConcreteProductB1";
}
}
(4)產品B2
/**
* 產品B2
*/
public class ConcreteProductB2 extends Product {
public ConcreteProductB2() {
name = "ConcreteProductB2";
}
}
3、創建創建者抽象類,並定義用來創建產品的工廠方法
創建者一般爲需要用到產品的類,需要的產品則通過類中的工廠方法創建。
/**
* 創建者抽象類
*/
public abstract class Creator {
/**
* 創建產品(工廠方法)
*/
protected abstract Product createProduct(String productType);
}
4、創建具體的創建者,並繼承創建者抽象類
具體的創建者需要實現創建產品的工廠方法。
(1)創建者1
/**
* 創建者1
*/
public class ConcreteCreator1 extends Creator {
@Override
protected Product createProduct(String productType) {
// 由具體的創建者(子類)決定創建哪個類的對象
if ("A".equals(productType)) {
return new ConcreteProductA1();
} else if ("B".equals(productType)) {
return new ConcreteProductB1();
}
return null;
}
}
(2)創建者2
/**
* 創建者2
*/
public class ConcreteCreator2 extends Creator {
@Override
protected Product createProduct(String productType) {
// 由具體的創建者(子類)決定創建哪個類的對象
if ("A".equals(productType)) {
return new ConcreteProductA2();
} else if ("B".equals(productType)) {
return new ConcreteProductB2();
}
return null;
}
}
5、創建者通過工廠方法創建產品
public class Test {
public static void main(String[] args) {
// 創建者1
Creator creator1 = new ConcreteCreator1();
// 創建者2
Creator creator2 = new ConcreteCreator2();
// 通過工廠方法創建產品
Product product = creator1.createProduct("A");
System.out.println("創建者1創建產品A:" + product.getName());
product = creator2.createProduct("A");
System.out.println("創建者2創建產品A:" + product.getName());
}
}
三、舉個栗子
1、背景
假設你有一個披薩店,出售多種類型的披薩:芝士披薩、蛤蜊披薩、素食披薩等。由於經營有成,你打算推廣自己的加盟店。
爲了確保加盟店運營的質量,你希望加盟店能夠採用固定的製作流程。但是由於區域的差異,每家加盟店都可能想要提供不同風味的披薩(比如紐約、芝加哥、加州),因此又必須允許加盟店能夠自由地製作該區域的風味。
2、實現
披薩店子類通過實現創建披薩方法來決定要創建什麼風味的披薩。
(1)創建披薩抽象類
/**
* 披薩抽象類
*/
public abstract class Pizza {
/**
* 名稱
*/
String name;
/**
* 麪糰
*/
String dough;
/**
* 醬料
*/
String sauce;
/**
* 佐料
*/
ArrayList<String> toppings = new ArrayList<>();
void prepare() {
System.out.println("Preparing " + name);
System.out.println("Tossing dough...");
System.out.println("Adding souce...");
System.out.println("Adding toppings: ");
for (int i = 0; i < toppings.size(); i++) {
System.out.println(" "+ toppings.get(i));
}
}
/**
* 烘烤
*/
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");
}
public String getName() {
return name;
}
}
(2)創建不同風味、不同類型的披薩
/**
* 紐約風味的芝士披薩
*/
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 NYStyleClamPizza extends Pizza {
public NYStyleClamPizza() {
name = "NY Style Sauce Clam Pizza";
dough = "Thin Crust Dough";
sauce = "Marinara Sauce";
toppings.add("Fresh Clams");
}
}
/**
* 芝加哥風味的芝士披薩
*/
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");
}
void cut() {
System.out.println("Cutting the pizza into square slices");
}
}
/**
* 芝加哥風味的蛤蜊披薩
*/
public class ChicagoStyleClamPizza extends Pizza {
public ChicagoStyleClamPizza() {
name = "Chicago Style Clam Pizza";
dough = "Extra Thick Crust Dough";
sauce = "Plum Tomato Sauce";
toppings.add("Frozen Clams");
}
void cut() {
System.out.println("Cutting the pizza into square slices");
}
}
(3)創建披薩店抽象類
/**
* 披薩店抽象類
*/
public abstract class PizzaStore {
/**
* 訂購披薩
*/
public Pizza orderPizza(String type) {
Pizza pizza = createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
/**
* 創建披薩(工廠方法)
*/
protected abstract Pizza createPizza(String type);
}
(4)創建不同風味的披薩店
/**
* 紐約風味披薩店
*/
public class NYStylePizzaStore extends PizzaStore {
@Override
protected Pizza createPizza(String type) {
Pizza pizza = null;
if ("cheese".equals(type)) {
pizza = new NYStyleCheesePizza();
} else if ("clam".equals(type)) {
pizza = new NYStyleClamPizza();
}
return pizza;
}
}
/**
* 芝加哥風味披薩店
*/
public class ChicagoStylePizzaStore extends PizzaStore {
@Override
protected Pizza createPizza(String type) {
Pizza pizza = null;
if ("cheese".equals(type)) {
pizza = new ChicagoStyleCheesePizza();
} else if ("clam".equals(type)) {
pizza = new ChicagoStyleClamPizza();
}
return pizza;
}
}
(5)使用不同風味的披薩店訂購披薩
public class Test {
public static void main(String[] args) {
// 紐約風味披薩店
PizzaStore nyStore = new NYStylePizzaStore();
// 芝加哥風味披薩店
PizzaStore chicagoStore = new ChicagoStylePizzaStore();
// 訂購芝士披薩
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");
}
}