正文
一、定義
工廠方法模式定義了一個建立物件的介面,但由子類決定要例項化的類是哪一個。工廠方法讓類把例項化推遲到子類。
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
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");
}
}