JavaRush /Blog Java /Random-VI /Mẫu thiết kế: FactoryMethod

Mẫu thiết kế: FactoryMethod

Xuất bản trong nhóm
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). Mẫu thiết kế: FactoryMethod - 1Bạ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:
  1. Kế thừa trong Java.
  2. 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
Mọi thứ đang diễn ra tốt đẹp với chúng tôi đến nỗi một ngày đẹp trời chúng tôi nhận ra mối quan tâm của OneAuto. Với tư cách là những nhà quản lý nhạy bén, chúng tôi không muốn mất khách hàng của OneAuto và nhiệm vụ của chúng tôi là cơ cấu lại hoạt động sản xuất theo cách mà chúng tôi có thể sản xuất:
  • xe sedan AutoRush
  • Toa xe ga AutoRush
  • coupe AutoRush
  • Xe sedan OneAuto
  • Toa xe ga OneAuto
  • coupe OneAuto
Như bạn có thể thấy, thay vì một nhóm sản phẩm phái sinh, hai nhóm sản phẩm phái sinh đã xuất hiện, khác nhau ở một số chi tiết. Mẫu thiết kế Factory Method giải quyết vấn đề tạo ra các nhóm sản phẩm khác nhau, mỗi nhóm có một số đặc điểm riêng. Chúng ta sẽ xem xét nguyên tắc của mẫu này trong thực tế, chuyển dần từ đơn giản đến phức tạp, sử dụng ví dụ về quán cà phê mà chúng ta đã tạo trong một trong những bài giảng trước .

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.
Điều duy nhất không thay đổi là mô hình kinh doanh của chúng tôi, mô hình này đã được chứng minh là tốt. Nếu chúng ta nói bằng ngôn ngữ mã thì đây là điều sẽ xảy ra. Chúng tôi đã có 4 loại sản phẩm:
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:
  1. Hãy trả lại phương thức createCoffee(CoffeeType type)cho lớp CoffeeShop.
  2. Hãy làm cho phương pháp này trở nên trừu tượng.
  3. Bản thân lớp học CoffeeShopsẽ trở nên trừu tượng.
  4. Lớp học CoffeeShopsẽ có người thừa kế.
Vâng, bạn ạ. Một quán cà phê Ý không gì khác hơn là người thừa kế đẳng cấp 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 Coffeetrừ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ó CoffeeShoptrở 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. Mẫu thiết kế: FactoryMethod - 2Có thể rút ra kết luận gì?
  1. Tất cả các sản phẩm đều là sự triển khai của lớp trừu tượng Coffee.
  2. 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.
  3. 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ỹ
  4. Siêu lớp CoffeeShopkhông có thông tin về việc triển khai sản phẩm cụ thể ( Coffee) nào sẽ được tạo.
  5. 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ó.
  6. Mỗi lớp con cháu CoffeeShopthực hiện một phương thức xuất xưởng createCoffee()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.
Bây giờ bạn đã sẵn sàng để xác định mẫu phương thức xuất xưởng . Mẫu phương thức xuất xưởng xác định giao diện để tạo một đối tượng, nhưng cho phép các lớp con chọn lớp của cá thể để tạo. Do đó, phương thức Factory ủy quyền thao tác khởi tạo cho các lớp con. Nói chung, việc nhớ định nghĩa không quan trọng bằng việc hiểu mọi thứ hoạt động như thế nào.

Cấu trúc phương pháp nhà máy

Mẫu thiết kế: FactoryMethod - 3Sơ đồ 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?
  1. 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.
  2. 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.
  3. Lớp này ConcreteCreatorthực hiện một phương thức factoryMethod()trực tiếp tạo ra một sản phẩm.
  4. 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.
  5. 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ể.

Bài tập về nhà

Vì vậy, hôm nay chúng ta đã làm khá nhiều việc và nghiên cứu mẫu thiết kế Factory Method. Đã đến lúc củng cố tài liệu bạn đã học! Nhiệm vụ 1. Làm việc để mở một quán cà phê khác. Nó có thể được làm theo phong cách tiếng Anh hoặc tiếng Tây Ban Nha. Hoặc thậm chí theo phong cách của một con tàu vũ trụ. Hãy thêm màu thực phẩm vào cà phê để nó tỏa sáng, và nhìn chung, cà phê sẽ chỉ là khoảng trống! Nhiệm vụ 2. Ở bài giảng trước, bạn có nhiệm vụ tạo một quán sushi ảo hoặc một tiệm bánh pizza ảo. Nhiệm vụ của bạn không phải là đứng yên. Hôm nay bạn đã học cách sử dụng mẫu phương thức xuất xưởng để đạt được thành công. Đã đến lúc tận dụng kiến ​​thức này và mở rộng hoạt động kinh doanh của riêng bạn ;)
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION