Xin chào! Hôm nay chúng ta sẽ tiếp tục nghiên cứu các mẫu thiết kế và nói về phương thức Factory (FactoryMethod). Bạn sẽ tìm ra nó là gì và mẫu này phù hợp với những nhiệm vụ gì. Chúng ta sẽ xem xét mẫu thiết kế này trong thực tế và khám phá cấu trúc của nó. Để làm rõ tất cả những điều trên, bạn cần hiểu các chủ đề sau:
- 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 được vấn đề gì?
Trong tất cả các mẫu thiết kế nhà máy, có hai nhóm tham gia - người sáng tạo (chính các nhà máy) và sản phẩm (các đối tượng do nhà máy tạo ra). Hãy tưởng tượng tình huống: chúng ta có một nhà máy sản xuất ô tô mang thương hiệu AutoRush. Cô ấy có thể tạo ra những mô hình ô tô với nhiều kiểu thân xe khác nhau:- xe sedan
- toa xe ga
- chiếc coupe
- xe sedan AutoRush
- Toa xe ga AutoRush
- coupe AutoRush
- Xe sedan OneAuto
- Toa xe ga OneAuto
- coupe OneAuto
Một chút về mẫu nhà máy
Hãy để tôi nhắc bạn: chúng tôi đã cùng bạn xây dựng một quán cà phê ảo nhỏ. Trong đó, chúng ta đã học cách tạo ra các loại cà phê khác nhau bằng cách sử dụng một nhà máy đơn giản. Hôm nay chúng ta sẽ tinh chỉnh ví dụ này. Hãy nhớ quán cà phê của chúng ta với một nhà máy đơn giản trông như thế nào. Chúng tôi đã có một lớp học cà phê:public class Coffee {
public void grindCoffee(){
// перемалываем кофе
}
public void makeCoffee(){
// делаем кофе
}
public void pourIntoCup(){
// наливаем в чашку
}
}
Và một số người thừa kế của ông - những loại cà phê cụ thể mà nhà máy của chúng tôi có thể sản xuất:
public class Americano extends Coffee {}
public class Cappuccino extends Coffee {}
public class CaffeLatte extends Coffee {}
public class Espresso extends Coffee {}
Để thuận tiện cho việc chấp nhận đơn đặt hàng, chúng tôi đã giới thiệu chuyển khoản:
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 là quán cà phê:
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("Вот ваш кофе! Спасибо, приходите еще!");
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 tốt. Nhiều đến mức chúng tôi đang nghĩ đến việc mở rộng. Chúng tôi muốn mở một số điểm mới. Là những người dám nghĩ dám làm, chúng tôi sẽ không tạo ra những quán cà phê đơn điệu. Tôi muốn mỗi người có một nét riêng. Vì vậy, để bắt đầu, chúng tôi sẽ mở ra hai điểm: theo phong cách Ý và Mỹ. Những thay đổi sẽ không chỉ ảnh hưởng đến nội thất mà còn ảnh hưởng đến đồ uống:- trong một 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.
- Phần ăn của Mỹ sẽ lớn hơn một chút và với mỗi đơn hàng, chúng tôi sẽ phục vụ kẹo dẻo tan chảy - kẹo dẻo.
public class Americano extends Coffee {}
public class Cappuccino extends Coffee {}
public class CaffeLatte extends Coffee {}
public class Espresso extends Coffee {}
Và nó trở thành 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 pháp này orderCoffee(CoffeeType type)
phải trải qua một số thay đổi tối thiểu. Chúng ta 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("Вот ваш кофе! Спасибо, приходите еще!");
return coffee;
}
Chúng ta có những lựa chọn nào? Chúng ta đã biết cách viết một nhà máy rồi phải không? Điều đơn giản nhất bạn nghĩ ngay đến là viết hai nhà máy tương tự, sau đó chuyển phần triển khai cần thiết đến quán cà phê của chúng ta trong hàm tạo. Khi đó đẳng cấp của quán cà phê sẽ không thay đổi. Đầu tiên, chúng ta cần tạo một lớp nhà máy mới, kế thừa từ nhà máy đơn giản của chúng ta và ghi đè lớp createCoffee (CoffeeType type)
. Hãy viết các nhà máy sản xuất cà phê theo phong cách Ý và 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 việc triển khai nhà máy cần thiết 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ụ: cappuccino theo phong cách Ý và Mỹ:
public class Main {
public static void main(String[] args) {
/*
Закажем капучино в итальянском стиле:
1. Создадим фабрику для приготовления итальянского кофе
2. Создадим новую кофейню, передав ей в конструкторе фабрику итальянского кофе
3. Закажем наш кофе
*/
SimpleItalianCoffeeFactory italianCoffeeFactory = new SimpleItalianCoffeeFactory();
CoffeeShop italianCoffeeShop = new CoffeeShop(italianCoffeeFactory);
italianCoffeeShop.orderCoffee(CoffeeType.CAPPUCCINO);
/*
Закажем капучино в американском стиле
1. Создадим фабрику для приготовления американского кофе
2. Создадим новую кофейню, передав ей в конструкторе фабрику американского кофе
3. Закажем наш кофе
*/
SimpleAmericanCoffeeFactory americanCoffeeFactory = new SimpleAmericanCoffeeFactory();
CoffeeShop americanCoffeeShop = new CoffeeShop(americanCoffeeFactory);
americanCoffeeShop.orderCoffee(CoffeeType.CAPPUCCINO);
}
}
Chúng tôi đã tạo ra hai quán cà phê khác nhau, chuyển mỗi quán đến nhà máy được yêu cầu. Một mặt, chúng tôi đã đạt được mục tiêu của mình, nhưng mặt khác... Có điều gì đó đang cào xé tâm hồn không thể kìm nén của người doanh nhân... Hãy cùng tìm hiểu xem có chuyện gì. Thứ nhất, sự phong phú của các nhà máy. Có thể tạo nhà máy của riêng bạn mỗi lần cho một điểm mới và ngoài ra, hãy đảm bảo rằng khi tạo quán cà phê, nhà máy cần thiết sẽ được chuyển cho người xây dựng? 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. Chúng tôi vẫn đang nghiên cứu một mẫu mới ở đây. Thứ ba, không thể làm khác được sao? Sẽ thật tuyệt nếu chúng ta có thể địa phương hóa tất cả các câu hỏi về pha cà phê trong lớp học CoffeeShop
, liên kết các quy trình tạo cà phê và phục vụ đơn hàng, nhưng đồng thời vẫn duy trì đủ tính linh hoạt để pha cà phê theo các phong cách khác nhau. Câu trả lời là có, bạn có thể. Đây được gọi là mẫu thiết kế phương thức nhà máy.
Từ một nhà máy đơn giản đến một phương pháp nhà máy
Để giải quyết vấn đề một cách hiệu quả nhất có thể, chúng tôi:- Hãy trả lại phương thức
createCoffee(CoffeeType type)
cho lớpCoffeeShop
. - Hãy làm cho phương pháp này trở nên trừu tượng.
- Bản thân lớp học
CoffeeShop
sẽ trở nên trừu tượng. - Lớp học
CoffeeShop
sẽ có người thừa kế.
CoffeeShop
, thực hiện một phương pháp createCoffee(CoffeeType type)
phù hợp với truyền thống tốt nhất của các thợ pha cà phê Ý. Vì vậy, theo thứ tự. Bước 1. Hãy làm cho lớp trở nên Coffee
trừu tượng. Bây giờ chúng tôi có hai dòng sản phẩm khác nhau. Đồ uống cà phê của Ý và Mỹ vẫn có chung một tổ tiên: Coffee
. Sẽ đúng nếu làm cho nó trừu tượng:
public abstract class Coffee {
public void makeCoffee(){
// делаем кофе
}
public void pourIntoCup(){
// наливаем в чашку
}
}
Bước 2. Làm cho nó CoffeeShop
trở nên trừu tượng bằng một phương thức trừu tượngcreateCoffee(CoffeeType type)
public abstract class CoffeeShop {
public Coffee orderCoffee(CoffeeType type) {
Coffee coffee = createCoffee(type);
coffee.makeCoffee();
coffee.pourIntoCup();
System.out.println("Вот ваш кофе! Спасибо, приходите еще!");
return coffee;
}
protected abstract Coffee createCoffee(CoffeeType type);
}
Bước 3. Tạo một quán cà phê Ý, một lớp hậu duệ của quán cà phê trừu tượng. Trong đó, chúng tôi triển khai phương pháp createCoffee(CoffeeType type)
có tính đến các chi tiết cụ thể của Ý.
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. Hãy làm tương tự với một quán cà phê kiểu 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. Chúng ta hãy xem việc gọi một ly latte kiểu Mỹ và Ý sẽ 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 trong quán cà phê của mình.
Phương pháp nhà máy hoạt động như thế nào
Bây giờ chúng ta hãy xem xét kỹ hơn những gì chúng ta có. Sơ đồ dưới đây cho thấy các lớp kết quả. Khối màu xanh lá cây là lớp người sáng tạo, khối màu xanh lam là lớp sản phẩm. Có thể rút ra kết luận gì?- Tất cả các sản phẩm đều là sự triển khai của lớp trừu tượng
Coffee
. - Tất cả những người sáng tạo đều là sự triển khai của lớp trừu tượng
CoffeeShop
. - Chúng tôi quan sát hai hệ thống phân cấp lớp song song:
- Thứ bậc của sản phẩm. Chúng ta thấy con cháu người Ý và con cháu người Mỹ
- Thứ bậc của người sáng tạo. Chúng ta thấy con cháu người Ý và con cháu người Mỹ
- Siêu lớp
CoffeeShop
không có thông tin về việc triển khai sản phẩm cụ thể (Coffee
) nào sẽ được tạo. - Một siêu lớp
CoffeeShop
ủy quyền việc tạo ra một sản phẩm cụ thể cho các lớp con của nó. - Mỗi lớp con cháu
CoffeeShop
thực hiện một phương thức xuất xưởngcreateCoffee()
phù hợp với đặc điểm riêng của nó. Nói cách khác, trong quá trình triển khai các lớp người sáng tạo, một quyết định được đưa ra là chuẩn bị một sản phẩm cụ thể dựa trên các đặc điểm cụ thể của lớp người sáng tạo.
Cấu trúc phương pháp nhà máy
Sơ đồ trên cho thấy cấu trúc chung của mẫu phương thức nhà máy. Còn điều gì quan trọng nữa ở đây?- Lớp Creator chứa phần triển khai của 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.
- Một phương thức trừu tượng
factoryMethod()
phải được thực hiện bởi tất cả các lớp con của lớp đóCreator
. - Lớp này
ConcreteCreator
thực hiện một phương thứcfactoryMethod()
trực tiếp tạo ra một 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 - 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 ở mức độ trừu tượng hơn là triển khai cụ thể.
GO TO FULL VERSION