CHÀO! Hôm nay chúng ta sẽ tiếp tục nghiên cứu về các mẫu thiết kế và chúng ta sẽ thảo luận về mẫu phương thức xuất xưởng.
Bạn sẽ tìm ra nó là gì và mẫu này phù hợp với những nhiệm vụ nào. Chúng ta sẽ xem xét mẫu thiết kế này trong thực tế và nghiên cứu cấu trúc của nó. Để đảm bảo mọi thứ rõ ràng, bạn cần hiểu các chủ đề sau:
Chúng ta có thể đưa ra kết luận gì?
Sơ đồ trên cho thấy cấu trúc chung của mẫu phương thức xuất xưởng. Điều gì khác là quan trọng ở đây?

- Kế thừa trong Java.
- Các phương thức và lớp trừu tượng trong Java
Phương pháp nhà máy giải quyết vấn đề gì?
Tất cả các mẫu thiết kế của nhà máy đều có hai loại người tham gia: người sáng tạo (chính nhà máy) và sản phẩm (đối tượng do nhà máy tạo ra). Hãy tưởng tượng tình huống sau: chúng tôi có một nhà máy sản xuất ô tô mang nhãn hiệu CodeGym. Nó biết cách tạo ra các mô hình ô tô với nhiều loại thân xe khác nhau:- xe sedan
- xe ga
- những chiếc coupe
- xe sedan CodeGym
- Toa xe ga CodeGym
- CodeGym coupe
- xe sedan OneAuto
- Xe ga OneAuto
- OneAuto coupe
Một chút về mô hình nhà máy
Hãy để tôi nhắc bạn rằng trước đây chúng tôi đã xây dựng một quán cà phê ảo nhỏ. Với sự trợ giúp của một nhà máy đơn giản, chúng tôi đã học cách tạo ra các loại cà phê khác nhau. Hôm nay chúng ta sẽ làm lại ví dụ này. Hãy nhớ lại quán cà phê của chúng ta trông như thế nào, với nhà máy đơn giản của nó. Chúng tôi đã có một lớp học cà phê:
public class Coffee {
public void grindCoffee(){
// Grind the coffee
}
public void makeCoffee(){
// Brew the coffee
}
public void pourIntoCup(){
// Pour into a cup
}
}
Và một số lớp con tương ứng với các loại cà phê cụ thể mà nhà máy chúng tôi sản xuất được:
public class Americano extends Coffee {}
public class Cappuccino extends Coffee {}
public class CaffeLatte extends Coffee {}
public class Espresso extends Coffee {}
Chúng tôi đã tạo một enum để dễ dàng đặt hàng:
public enum CoffeeType {
ESPRESSO,
AMERICANO,
CAFFE_LATTE,
CAPPUCCINO
}
Bản thân nhà máy cà phê trông như thế này:
public class SimpleCoffeeFactory {
public Coffee createCoffee(CoffeeType type) {
Coffee coffee = null;
switch (type) {
case AMERICANO:
coffee = new Americano();
break;
case ESPRESSO:
coffee = new Espresso();
break;
case CAPPUCCINO:
coffee = new Cappuccino();
break;
case CAFFE_LATTE:
coffee = new CaffeLatte();
break;
}
return coffee;
}
}
Và cuối cùng, quán cà phê trông như thế này:
public class CoffeeShop {
private final SimpleCoffeeFactory coffeeFactory;
public CoffeeShop(SimpleCoffeeFactory coffeeFactory) {
this.coffeeFactory = coffeeFactory;
}
public Coffee orderCoffee(CoffeeType type) {
Coffee coffee = coffeeFactory.createCoffee(type);
coffee.grindCoffee();
coffee.makeCoffee();
coffee.pourIntoCup();
System.out.println("Here's your coffee! Thanks! Come again!");
return coffee;
}
}
Hiện đại hóa một nhà máy đơn giản
Quán cà phê của chúng tôi đang hoạt động rất tốt. Nhiều đến mức chúng tôi đang xem xét mở rộng. Chúng tôi muốn mở một số địa điểm mới. Chúng tôi táo bạo và dám nghĩ dám làm, vì vậy chúng tôi sẽ không tạo ra những quán cà phê nhàm chán. Chúng tôi muốn mỗi cửa hàng có một sự thay đổi đặc biệt. Theo đó, để bắt đầu, chúng tôi sẽ mở hai địa điểm: một ở Ý và một ở Mỹ. Những thay đổi này sẽ không chỉ ảnh hưởng đến thiết kế nội thất mà còn ảnh hưởng đến đồ uống được cung cấp:- trong quán cà phê Ý, chúng tôi sẽ sử dụng các nhãn hiệu cà phê độc quyền của Ý, với cách xay và rang đặc biệt.
- địa điểm ở Mỹ sẽ có những phần ăn lớn hơn và chúng tôi sẽ phục vụ kẹo dẻo với mỗi đơn hàng.
public class Americano extends Coffee {}
public class Cappuccino extends Coffee {}
public class CaffeLatte extends Coffee {}
public class Espresso extends Coffee {}
Nhưng bây giờ chúng ta sẽ có 8:
public class ItalianStyleAmericano extends Coffee {}
public class ItalianStyleCappucino extends Coffee {}
public class ItalianStyleCaffeLatte extends Coffee {}
public class ItalianStyleEspresso extends Coffee {}
public class AmericanStyleAmericano extends Coffee {}
public class AmericanStyleCappucino extends Coffee {}
public class AmericanStyleCaffeLatte extends Coffee {}
public class AmericanStyleEspresso extends Coffee {}
Vì chúng tôi muốn giữ nguyên mô hình kinh doanh hiện tại nên chúng tôi muốn phương orderCoffee(CoffeeType type)
pháp này trải qua càng ít thay đổi càng tốt. Hãy nhìn vào nó:
public Coffee orderCoffee(CoffeeType type) {
Coffee coffee = coffeeFactory.createCoffee(type);
coffee.grindCoffee();
coffee.makeCoffee();
coffee.pourIntoCup();
System.out.println("Here's your coffee! Thanks! Come again!");
return coffee;
}
Chúng ta có những lựa chọn nào? Chà, chúng ta đã biết cách viết nhà máy rồi phải không? Điều đơn giản nhất ngay lập tức xuất hiện trong đầu là viết hai nhà máy tương tự, sau đó chuyển cách triển khai mong muốn cho người xây dựng quán cà phê của chúng ta. Bằng cách này, đẳng cấp của quán cà phê sẽ không thay đổi. Trước tiên, chúng ta cần tạo một lớp nhà máy mới, làm cho nó kế thừa nhà máy đơn giản của chúng ta, sau đó ghi đè phương createCoffee(CoffeeType type)
thức. Hãy viết các nhà máy để tạo ra cà phê kiểu Ý và cà phê kiểu Mỹ:
public class SimpleItalianCoffeeFactory extends SimpleCoffeeFactory {
@Override
public Coffee createCoffee(CoffeeType type) {
Coffee coffee = null;
switch (type) {
case AMERICANO:
coffee = new ItalianStyleAmericano();
break;
case ESPRESSO:
coffee = new ItalianStyleEspresso();
break;
case CAPPUCCINO:
coffee = new ItalianStyleCappuccino();
break;
case CAFFE_LATTE:
coffee = new ItalianStyleCaffeLatte();
break;
}
return coffee;
}
}
public class SimpleAmericanCoffeeFactory extends SimpleCoffeeFactory{
@Override
public Coffee createCoffee (CoffeeType type) {
Coffee coffee = null;
switch (type) {
case AMERICANO:
coffee = new AmericanStyleAmericano();
break;
case ESPRESSO:
coffee = new AmericanStyleEspresso();
break;
case CAPPUCCINO:
coffee = new AmericanStyleCappuccino();
break;
case CAFFE_LATTE:
coffee = new AmericanStyleCaffeLatte();
break;
}
return coffee;
}
}
Bây giờ chúng ta có thể chuyển cài đặt nhà máy mong muốn cho CoffeeShop. Hãy xem mã đặt hàng cà phê từ các cửa hàng cà phê khác nhau sẽ như thế nào. Ví dụ: cà phê cappuccino kiểu Ý và kiểu Mỹ:
public class Main {
public static void main(String[] args) {
/*
Order an Italian-style cappuccino:
1. Create a factory for making Italian coffee
2. Create a new coffee shop, passing the Italian coffee factory to it through the constructor
3. Order our coffee
*/
SimpleItalianCoffeeFactory italianCoffeeFactory = new SimpleItalianCoffeeFactory();
CoffeeShop italianCoffeeShop = new CoffeeShop(italianCoffeeFactory);
italianCoffeeShop.orderCoffee(CoffeeType.CAPPUCCINO);
/*
Order an American-style cappuccino
1. Create a factory for making American coffee
2. Create a new coffee shop, passing the American coffee factory to it through the constructor
3. Order our coffee
*/
SimpleAmericanCoffeeFactory americanCoffeeFactory = new SimpleAmericanCoffeeFactory();
CoffeeShop americanCoffeeShop = new CoffeeShop(americanCoffeeFactory);
americanCoffeeShop.orderCoffee(CoffeeType.CAPPUCCINO);
}
}
Chúng tôi đã tạo ra hai cửa hàng cà phê khác nhau, chuyển nhà máy mong muốn cho mỗi cửa hàng. Một mặt, chúng tôi đã hoàn thành mục tiêu của mình, nhưng mặt khác... Bằng cách nào đó, điều này không phù hợp với các doanh nhân... Hãy tìm ra điều gì sai. Đầu tiên, sự phong phú của các nhà máy. Cái gì? Giờ đây, đối với mọi địa điểm mới, chúng tôi phải tạo nhà máy của riêng mình và ngoài ra, đảm bảo rằng nhà máy có liên quan được chuyển cho người xây dựng khi tạo quán cà phê? Thứ hai, nó vẫn là một nhà máy đơn giản. Chỉ cần hiện đại hóa một chút. Nhưng chúng ta ở đây để học một khuôn mẫu mới. Thứ ba, không phải là một cách tiếp cận khác có thể? Sẽ thật tuyệt nếu chúng ta có thể đưa tất cả các vấn đề liên quan đến pha chế cà phê vàoCoffeeShop
đẳng cấp bằng cách liên kết các quy trình tạo ra cà phê và phục vụ các đơn đặt hàng, đồng thời duy trì đủ tính linh hoạt để tạo ra nhiều phong cách cà phê khác nhau. Câu trả lời là có, chúng ta có thể. Đây được gọi là mẫu thiết kế phương thức xuất xưởng.
Từ một nhà máy đơn giản đến một phương pháp nhà máy
Để giải quyết công việc hiệu quả nhất có thể:- Chúng tôi trả lại
createCoffee(CoffeeType type)
phương thức choCoffeeShop
lớp. - Chúng ta sẽ làm cho phương thức này trở nên trừu tượng.
- Bản thân lớp
CoffeeShop
sẽ trở nên trừu tượng. - Lớp
CoffeeShop
sẽ có các lớp con.
CoffeeShop
lớp thực hiện createCoffee(CoffeeType type)
phương pháp phù hợp với truyền thống tốt nhất của baristas Ý. Bây giờ, từng bước một. Bước 1. Tạo Coffee
lớp trừu tượng. Chúng tôi có hai dòng sản phẩm khác nhau. Tuy nhiên, cà phê Ý và cà phê Mỹ có một tổ tiên chung - đẳng Coffee
cấp. Nó sẽ là thích hợp để làm cho nó trừu tượng:
public abstract class Coffee {
public void makeCoffee(){
// Brew the coffee
}
public void pourIntoCup(){
// Pour into a cup
}
}
Bước 2. Tạo CoffeeShop
trừu tượng, với một createCoffee(CoffeeType type)
phương thức trừu tượng
public abstract class CoffeeShop {
public Coffee orderCoffee(CoffeeType type) {
Coffee coffee = createCoffee(type);
coffee.makeCoffee();
coffee.pourIntoCup();
System.out.println("Here's your coffee! Thanks! Come again!");
return coffee;
}
protected abstract Coffee createCoffee(CoffeeType type);
}
Bước 3. Tạo một quán cà phê kiểu Ý, là hậu duệ của quán cà phê trừu tượng. Chúng tôi triển khai createCoffee(CoffeeType type)
phương pháp trong đó, có tính đến các chi tiết cụ thể của người nhận ở Ý.
public class ItalianCoffeeShop extends CoffeeShop {
@Override
public Coffee createCoffee (CoffeeType type) {
Coffee coffee = null;
switch (type) {
case AMERICANO:
coffee = new ItalianStyleAmericano();
break;
case ESPRESSO:
coffee = new ItalianStyleEspresso();
break;
case CAPPUCCINO:
coffee = new ItalianStyleCappuccino();
break;
case CAFFE_LATTE:
coffee = new ItalianStyleCaffeLatte();
break;
}
return coffee;
}
}
Bước 4. Ta làm tương tự với quán cà phê phong cách Mỹ
public class AmericanCoffeeShop extends CoffeeShop {
@Override
public Coffee createCoffee(CoffeeType type) {
Coffee coffee = null;
switch (type) {
case AMERICANO:
coffee = new AmericanStyleAmericano();
break;
case ESPRESSO:
coffee = new AmericanStyleEspresso();
break;
case CAPPUCCINO:
coffee = new AmericanStyleCappuccino();
break;
case CAFFE_LATTE:
coffee = new AmericanStyleCaffeLatte();
break;
}
return coffee;
}
}
Bước 5. Kiểm tra xem latte của Mỹ và Ý trông như thế nào:
public class Main {
public static void main(String[] args) {
CoffeeShop italianCoffeeShop = new ItalianCoffeeShop();
italianCoffeeShop.orderCoffee(CoffeeType.CAFFE_LATTE);
CoffeeShop americanCoffeeShop = new AmericanCoffeeShop();
americanCoffeeShop.orderCoffee(CoffeeType.CAFFE_LATTE);
}
}
Chúc mừng. Chúng tôi vừa triển khai mẫu thiết kế phương pháp nhà máy bằng cách sử dụng quán cà phê của mình làm ví dụ.
Nguyên tắc đằng sau phương pháp nhà máy
Bây giờ hãy xem xét chi tiết hơn những gì chúng ta có. Sơ đồ dưới đây cho thấy các lớp kết quả. Các khối màu xanh lá cây là các lớp người sáng tạo và các khối màu xanh lam là các lớp sản phẩm.
- Tất cả các sản phẩm là triển khai của
Coffee
lớp trừu tượng. - Tất cả những người tạo là triển khai của
CoffeeShop
lớp trừu tượng. - Chúng tôi thấy hai hệ thống phân cấp lớp song song:
- Thứ bậc của sản phẩm. Chúng tôi thấy hậu duệ người Ý và hậu duệ người Mỹ
- Thứ bậc của người sáng tạo. Chúng tôi thấy hậu duệ người Ý và hậu duệ người Mỹ
- Lớp
CoffeeShop
cha không có thông tin về sản phẩm cụ thể (Coffee
) nào sẽ được tạo. - Lớp
CoffeeShop
cha ủy thác việc tạo ra một sản phẩm cụ thể cho các lớp con của nó. - Mỗi hậu duệ của
CoffeeShop
lớp thực hiện mộtcreateCoffee()
phương thức xuất xưởng phù hợp với các tính năng cụ thể của riêng nó. Nói cách khác, việc triển khai các lớp nhà sản xuất chuẩn bị các sản phẩm cụ thể dựa trên các chi tiết cụ thể của lớp nhà sản xuất.
Cấu trúc của một phương pháp nhà máy

- Lớp Creator triển khai tất cả các phương thức tương tác với sản phẩm, ngoại trừ phương thức xuất xưởng.
- Phương thức trừu tượng
factoryMethod()
phải được thực hiện bởi tất cả các hậu duệ củaCreator
lớp. - Lớp
ConcreteCreator
thực hiệnfactoryMethod()
phương thức trực tiếp tạo ra sản phẩm. - Lớp này chịu trách nhiệm tạo ra các sản phẩm cụ thể. Đây là lớp duy nhất có thông tin về việc tạo ra các sản phẩm này.
- Tất cả các sản phẩm phải triển khai một giao diện chung, tức là chúng phải là hậu duệ của một lớp sản phẩm chung. Điều này là cần thiết để các lớp sử dụng sản phẩm có thể hoạt động trên chúng dưới dạng trừu tượng, thay vì triển khai cụ thể.
GO TO FULL VERSION