JavaRush /Blog Java /Random-VI /Phương thức nhà máy và các mẫu nhà máy trừu tượng

Phương thức nhà máy và các mẫu nhà máy trừu tượng

Xuất bản trong nhóm
Trong cuốn sách “Đầu tiên. Design Patterns” định nghĩa các mẫu này như sau: Mẫu Factory Method 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ể sẽ được tạo. Do đó, phương thức Factory ủy quyền thao tác khởi tạo cho các lớp con. Mẫu Tóm tắt Factory cung cấp một giao diện để tạo các họ các đối tượng có liên quan hoặc phụ thuộc lẫn nhau mà không chỉ định các lớp cụ thể của chúng. Chúng ta hãy cố gắng hiểu điều này chi tiết hơn. Giả sử bạn quyết định viết một trò chơi về những người quyết định trở thành... (bạn cần một cái gì đó độc đáo và khác thường ở đây) nhà sư. Chúng ta có thể bắt đầu với những điều sau đây. 1) Tạo một lớp Monk và các lớp con (trước tiên hãy tạo một lớp):
public abstract class Monk {

    public abstract void description();
}
public class OrthodoxMonk extends Monk {
    @Override
    public void description() {
        System.out.println("Я православный монах");
    }
}
2) Và tất nhiên, hãy tạo một lớp Tu viện, trong đó bạn có thể thực hiện “lời khấn xuất gia”:
public class Monastery {
    private Monk monk;

    public void createMonk(String typeName) {
        this.monk = switch (typeName) {
            case "ORTODOX" -> new OrthodoxMonk();
            default -> null;
        };
    }

    public Monk getMonk() {
        return monk;
    }
}
Nào, hãy kiểm tra kết quả:
public class Main {
    public static void main(String[] args) {
        Monastery monastery = new Monastery();
        monastery.createMonk("ORTODOX");
        monastery.getMonk().description();
    }
}
Я православный монах
Bây giờ nếu bạn cần tạo... một tu sĩ Công giáo, bạn sẽ cần A) Tạo một lớp mới cho một tu sĩ Công giáo:
public class CatholicMonk extends Monk {
    @Override
    public void description() {
        System.out.println("Я католический монах");
    }
}
B) Thực hiện các thay đổi đối với lớp tu viện:
public class Monastery {
    private Monk monk;

    public void createMonk(String typeName) {
        this.monk = switch (typeName) {
            case "ORTODOX" -> new OrthodoxMonk();
            case "CATHOLIC" -> new CatholicMonk();
            default -> null;
        };
    }

    public Monk getMonk() {
        return monk;
    }
}
và vì vậy mỗi khi các loại tu sĩ mới được giới thiệu, bạn sẽ phải tạo một lớp mới và chỉnh sửa lớp hiện có. Có thể làm gì trong trường hợp này để bằng cách nào đó “đóng gói” lớp tu viện của chúng ta khỏi những thay đổi. Bạn có thể thử sử dụng mẫu Phương thức xuất xưởng. Nó sẽ trông như thế nào A) Hãy để nguyên lớp tu sĩ, ngoại trừ có lẽ thêm một tu sĩ Anh giáo (không chỉ người Công giáo và Cơ đốc giáo Chính thống mới có tu viện):
public abstract class Monk {

    public abstract void description();
}
public class OrthodoxMonk extends Monk {
    @Override
    public void description() {
        System.out.println("Я православный монах");
    }
}
public class CatholicMonk extends Monk {
    @Override
    public void description() {
        System.out.println("Я католический монах");
    }
}
public class AnglicanMonk extends Monk {
    @Override
    public void description() {
        System.out.println("Я англиканский монах");
    }
}
B) Hãy thay đổi lớp tu viện như sau (hãy làm cho nó và phương thức của nó trở nên trừu tượng). Ở đây chúng ta chỉ sử dụng phương thức Factory:
public abstract class Monastery {
    protected abstract Monk createMonk();
}
và tạo các lớp con với việc triển khai phương thức:
public class OrthodoxMonastery extends Monastery {
    @Override
    protected Monk createMonk() {
        return new OrthodoxMonk();
    }
}
public class CatholicMonastery extends Monastery {
    @Override
    protected Monk createMonk() {
        return new CatholicMonk();
    }
}
public class AnglicanMonastery extends Monastery {
    @Override
    protected Monk createMonk() {
        return new AnglicanMonk();
    }
}
B) Hãy kiểm tra mã
public class Main {
    public static void main(String[] args) {
        Monastery monastery;

        monastery = new OrthodoxMonastery();
        monastery.createMonk().description();

        monastery = new CatholicMonastery();
        monastery.createMonk().description();

        monastery = new AnglicanMonastery();
        monastery.createMonk().description();
    }
}
Я православный монах
Я католический монах
Я англиканский монах
Những thứ kia. như chúng ta thấy hiện nay, khi thêm các loại tu sĩ mới, sẽ không cần phải thay đổi các lớp hiện có mà chỉ cần thêm các loại mới nếu cần thiết (lớp của một tu viện và tu sĩ cụ thể). Có lẽ ai đó đã nhận thấy rằng phương thức mô tả, ngay từ đầu trong lớp Monk, cũng là Factory :) Định nghĩa của phương thức Factory nói rằng mẫu của chúng ta xác định giao diện để tạo một đối tượng, nhưng chúng ta không tạo bất kỳ giao diện, mặc dù chúng ta có thể tạo lớp Tu viện làm giao diện và triển khai nó trong các triển khai cụ thể. Điều này đề cập đến từ "giao diện" theo nghĩa rộng hơn. Định nghĩa cũng nói rằng nó cho phép các lớp con chọn lớp của cá thể mà chúng tạo ra . Ở đây chúng ta chỉ thấy rằng các lớp con (các lớp con) thực hiện phương thức này (nghĩa là những quyền tạo ra các đối tượng tu sĩ được ủy quyền cho chúng). Bây giờ chúng ta hãy mở rộng chương trình của chúng ta một chút, giới thiệu khả năng có những tu sĩ khác nhau trong giáo phái này hay giáo phái khác. Ví dụ, trong Chính thống giáo, dựa trên quan điểm của Giáo hội Chính thống về tu viện và tu sĩ (được thông qua tại Hội đồng Giám mục của Giáo hội Chính thống Nga ngày 29 tháng 11 - 2 tháng 12 năm 2017), chúng ta có thể kết luận rằng có 2 loại tu sĩ. : - Lược đồ nhỏ hơn (lớp phủ). - Lược đồ (lược đồ lớn). Ngoài ra còn có những “giai đoạn chuẩn bị”, nhưng mọi người không được coi là tu sĩ (Trudnik, Novice và Ryasophor hoặc Monk), vì họ không phát nguyện xuất gia. Vì vậy, chúng tôi không tính đến chúng. Chúng ta nhận được gì trong trường hợp này: A) Lớp Tu viện (để đơn giản hóa, bây giờ chúng ta hãy tập trung vào chủ nghĩa tu viện Chính thống) với phương thức Factory :
public abstract class Monastery {
    protected abstract Monk createMonk(String type);
}
và một tu viện cụ thể
public class OrthodoxMonastery extends Monastery {

    @Override
    protected Monk createMonk(String type) {
        return new OrthodoxMonk(type);
    }
}
B) Hãy sửa lớp tu sĩ:
public abstract class Monk {
    String kind;

    public Monk(String kind) {
        this.kind = kind;
    }

    public abstract void description();
}
và lớp con:
public class OrthodoxMonk extends Monk {
    public OrthodoxMonk(String kind) {
        super(kind);
    }

    @Override
    public void description() {
        System.out.println("Я православный монах - " + kind);
    }
}
C) Hãy kiểm tra mã của chúng tôi:
public class Main {
    public static void main(String[] args) {
        Monastery monastery = new OrthodoxMonastery();
        monastery.createMonk("Мантийный монах").description();
        monastery.createMonk("Великосхимник").description();
    }
}
Я православный монах - Мантийный монах
Я православный монах — Великосхимник
Do đó, bằng cách sử dụng mẫu Factory Method, chúng tôi đã đạt được rằng chúng tôi không phải thay đổi các lớp đã viết trước đó mà còn khi mở rộng hình ảnh (loại) các nhà sư, cần phải có những thay đổi tối thiểu trong mã. Hãy kiểm tra và thêm tất cả các mệnh lệnh và giáo đoàn của các tu sĩ Công giáo :) Nhưng tốt hơn nên tập trung vào 3 mệnh lệnh nổi tiếng nhất, vì có hơn 100 mệnh lệnh trong số đó: 1) Benedictine 2) Dòng Tên 3) Franciscan Để làm điều này, như trước đây với tu sĩ Chính thống giáo, chúng ta cần thực hiện một lớp tu sĩ Công giáo cụ thể:
public class CatholicMonk extends Monk {
    public CatholicMonk(String kind) {
        super(kind);
    }

    @Override
    public void description() {
        System.out.println("Я католический монах - " + kind);
    }
}
và lớp tu viện:
public class CatholicMonastery extends Monastery {

    @Override
    protected Monk createMonk(String type) {
        return new CatholicMonk(type);
    }
}
và kiểm tra mã:
public class Main {
    public static void main(String[] args) {
        Monastery monastery;

        monastery = new OrthodoxMonastery();
        monastery.createMonk("Мантийный монах").description();
        monastery.createMonk("Великосхимник").description();

        monastery = new CatholicMonastery();
        monastery.createMonk("Бенедиктинец").description();
        monastery.createMonk("Иезуит").description();
        monastery.createMonk("Францисканец").description();
    }
}
Я православный монах - Мантийный монах
Я православный монах - Великосхимник
Я католический монах - Бенедиктинец
Я католический монах - Иезуит
Я католический монах - Францисканец
Hãy kết thúc với mẫu này. Tất cả các loại tu sĩ này cũng có thể được thêm trước vào lớp E-num, nhưng để đơn giản hóa mã, chúng tôi sẽ thực hiện mà không cần nó. Đã đến lúc sử dụng mẫu Tóm tắt Factory. Chúng ta có các tu sĩ, bây giờ chúng ta có thể may cho họ quần áo, tràng hạt, v.v. Hãy bắt đầu với quần áo, tức là nếu chúng ta quay lại định nghĩa ban đầu, quần áo sẽ trở thành một nhóm gồm những đồ vật có mối liên hệ với nhau hoặc phụ thuộc lẫn nhau . Hãy bắt đầu với vấn đề mỗi loại tu sĩ đều có bộ y khác nhau. Nếu chúng ta thêm Phật giáo vào, thì chúng sẽ hoàn toàn khác :) Để làm điều này, chúng ta có thể tạo một giao diện nhà máy, việc triển khai giao diện này sẽ tạo ra quần áo cần thiết. Vì vậy A) Chúng tôi thành lập một nhà máy sản xuất quần áo
public interface MonkFactory {
    Clothing createClothing();
}
và việc thực hiện nó
public class OrthodoxMonkFactory implements MonkFactory {

        @Override
    public Clothing createClothing() {
        return new OrtodoxClothing();
    }
}
public class CatholicMonkFactory implements MonkFactory {

    @Override
    public Clothing createClothing() {
        return new CatholicClothing();
    }
}
public class AnglicanMonkFactory implements MonkFactory {

    @Override
    public Clothing createClothing() {
        return new AnglicanClothing();
    }
}
Chà, đừng quên các tu sĩ Phật giáo :)
public class BuddhistMonkFactory implements MonkFactory {

    @Override
    public Clothing createClothing() {
        return new BuddhistClothing();
    }
}
B) Tạo một lớp trang phục (để đơn giản hóa, hãy lấy yếu tố chính là trang phục của các nhà sư, chúng ta sẽ không đi sâu vào chi tiết):
public abstract class Clothing {
    private String name;

    public Clothing(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}
và lớp trẻ
public class OrtodoxClothing extends Clothing {
    public OrtodoxClothing() {
        super("Мантия");
    }
}
public class CatholicClothing extends Clothing {
    public CatholicClothing() {
        super("Ряса с капюшоном");
    }
}
public class AnglicanClothing extends Clothing {
    public AnglicanClothing() {
        super("Ряса");
    }
}
public class BuddhistClothing extends Clothing {
    public BuddhistClothing() {
        super("Кашая");
    }
}
C) Tiếp theo, chúng ta thay đổi lớp tu sĩ để họ có quần áo:
public abstract class Monk {
    String kind;
    Clothing clothing;

    public Monk(String kind) {
        this.kind = kind;
    }

    public void setClothing(Clothing clothing) {
        this.clothing = clothing;
    }

    public abstract void description();
}
public class OrthodoxMonk extends Monk {
    public OrthodoxMonk(String kind) {
        super(kind);
    }

    @Override
    public void description() {
        System.out.println("Я православный монах - " + kind);
        System.out.println("Моя одежда - " + clothing.getName());
    }
}
public class CatholicMonk extends Monk {
    public CatholicMonk(String kind) {
        super(kind);
    }

    @Override
    public void description() {
        System.out.println("Я католический монах - " + kind);
        System.out.println("Моя одежда - " + clothing.getName());
    }
}
public class AnglicanMonk extends Monk {
    public AnglicanMonk(String kind) {
        super(kind);
    }

    @Override
    public void description() {
        System.out.println("Я англиканский монах - " + kind);
        System.out.println("Моя одежда - " + clothing.getName());
    }
}
public class BuddhistMonk extends Monk {
    public BuddhistMonk(String kind) {
        super(kind);
    }

    @Override
    public void description() {
        System.out.println("Я буддийский монах - " + kind);
        System.out.println("Моя одежда - " + clothing.getName());
    }
}
D) Lớp tu viện chứa phương thức Factory của chúng tôi
public abstract class Monastery {

    public Monk create(MonkFactory monkFactory, String type) {
        Monk monk = createMonk(type);
        monk.setClothing(monkFactory.createClothing());
        return monk;
    }

    protected abstract Monk createMonk(String type);
}
việc triển khai của chúng tôi không thay đổi
public class OrthodoxMonastery extends Monastery {

    @Override
    protected Monk createMonk(String type) {
        return new OrthodoxMonk(type);
    }
}
public class CatholicMonastery extends Monastery {

    @Override
    protected Monk createMonk(String type) {
        return new CatholicMonk(type);
    }
}
public class AnglicanMonastery extends Monastery {

    @Override
    protected Monk createMonk(String type) {
        return new AnglicanMonk(type);
    }
}
public class BuddhistMonastery extends Monastery {

    @Override
    protected Monk createMonk(String type) {
        return new BuddhistMonk(type);
    }
}
đ) Kiểm tra kết quả:
public class Main {
    public static void main(String[] args) {
        Monastery monastery;

        monastery = new OrthodoxMonastery();
        monastery.create(new OrthodoxMonkFactory(), "Мантийный монах").description();

        monastery = new CatholicMonastery();
        monastery.create(new CatholicMonkFactory(), "Иезуит").description();

        monastery = new AnglicanMonastery();
        monastery.create(new AnglicanMonkFactory(), "Бенедиктинец").description();

        monastery = new BuddhistMonastery();
        monastery.create(new BuddhistMonkFactory(), "Монах").description();
    }
}
Я православный монах - Мантийный монах
Моя одежда - Мантия
Я католический монах - Иезуит
Моя одежда - Ряса с капюшоном
Я англиканский монах - Бенедиктинец
Моя одежда - Ряса
Я буддийский монах - Монах
Моя одежда - Кашая
Nhà máy sản xuất quần áo đã bắt đầu hoạt động tốt. Giờ đây, bạn có thể bổ sung thêm vào nhà máy việc sản xuất thiết bị dành cho các nhà sư để cầu nguyện thành công (chuỗi tràng hạt, v.v.). Nhưng câu hỏi vẫn còn đó là có thể sử dụng 2 mẫu cùng nhau không? Tất nhiên là bạn có thể :) Hãy thử tạo phiên bản cuối cùng của dự án của chúng ta và thêm một tu sĩ Hindu: A) Các nhà máy hiện tạo ra âm thanh của các nhà sư giống như một “nhà máy sao” :
public interface MonkFactory {
    Monk createMonk(String type);
    Clothing createClothing();
}
public class OrthodoxMonkFactory implements MonkFactory {

    @Override
    public Monk createMonk(String type){
        return new OrthodoxMonk(type);
    }

    @Override
    public Clothing createClothing() {
        return new OrtodoxClothing();
    }
}
public class CatholicMonkFactory implements MonkFactory {

    @Override
    public Monk createMonk(String type){
        return new CatholicMonk(type);
    }

    @Override
    public Clothing createClothing() {
        return new CatholicClothing();
    }
}
public class AnglicanMonkFactory implements MonkFactory {

    @Override
    public Monk createMonk(String type){
        return new AnglicanMonk(type);
    }

    @Override
    public Clothing createClothing() {
        return new AnglicanClothing();
    }
}
public class BuddhistMonkFactory implements MonkFactory {

    @Override
    public Monk createMonk(String type){
        return new BuddhistMonk(type);
    }

    @Override
    public Clothing createClothing() {
        return new BuddhistClothing();
    }
}
public class HinduMonkFactory implements MonkFactory {

    @Override
    public Monk createMonk(String type){
        return new HinduMonk(type);
    }

    @Override
    public Clothing createClothing() {
        return new HinduClothing();
    }
}
B) Lớp tu viện + việc triển khai cụ thể của lớp Tu viện là không cần thiết, chúng được thực hiện bởi nhà máy (ngược lại, chúng ta có thể bỏ chúng và loại bỏ các nhà máy, nhưng về bản chất thì chúng sẽ chỉ đơn giản là thay vì các nhà máy, chỉ trong trong trường hợp này, Tu viện sẽ phải được tạo thành một giao diện chứ không phải lớp trừu tượng). Và thêm lớp ứng dụng:
public class Application {

    public Monk create(MonkFactory monkFactory, String type) {
        Monk monk = monkFactory.createMonk(type);
        monk.prepare(monkFactory);
        return monk;
    }
}
B) Các nhà sư bây giờ chứa
public abstract class Monk {
    String kind;
    Clothing clothing;

    public Monk(String kind) {
        this.kind = kind;
    }

    public void setClothing(Clothing clothing) {
        this.clothing = clothing;
    }

    public abstract void description();

    public abstract void prepare(MonkFactory monkFactory);
}
chứa một phương thức xuất xưởng trong quá trình triển khai, được triển khai bằng cách sử dụng một nhà máy:
public class OrthodoxMonk extends Monk {

    public OrthodoxMonk(String kind) {
        super(kind);
    }

    @Override
    public void description() {
        System.out.println("Я православный монах - " + kind);
        System.out.println("Моя одежда - " + clothing.getName());
    }

    @Override
    public void prepare(MonkFactory monkFactory) {
        setClothing(monkFactory.createClothing());
    }
}
public class CatholicMonk extends Monk {
    public CatholicMonk(String kind) {
        super(kind);
    }

    @Override
    public void description() {
        System.out.println("Я католический монах - " + kind);
        System.out.println("Моя одежда - " + clothing.getName());
    }

    @Override
    public void prepare(MonkFactory monkFactory) {
        setClothing(monkFactory.createClothing());
    }
}
public class AnglicanMonk extends Monk {
    public AnglicanMonk(String kind) {
        super(kind);
    }

    @Override
    public void description() {
        System.out.println("Я англиканский монах - " + kind);
        System.out.println("Моя одежда - " + clothing.getName());
    }

    @Override
    public void prepare(MonkFactory monkFactory) {
        setClothing(monkFactory.createClothing());
    }
}
public class BuddhistMonk extends Monk {
    public BuddhistMonk(String kind) {
        super(kind);
    }

    @Override
    public void description() {
        System.out.println("Я буддийский монах - " + kind);
        System.out.println("Моя одежда - " + clothing.getName());
    }

    @Override
    public void prepare(MonkFactory monkFactory) {
        setClothing(monkFactory.createClothing());
    }
}
public class HinduMonk extends Monk {
    public HinduMonk(String kind) {
        super(kind);
    }

    @Override
    public void description() {
        System.out.println("Я индуистский монах - " + kind);
        System.out.println("Моя одежда - " + clothing.getName());
    }

    @Override
    public void prepare(MonkFactory monkFactory) {
        setClothing(monkFactory.createClothing());
    }
}
D) Và hãy kiểm tra:
public class Main {
    public static void main(String[] args) {
        Application application = new Application();

        application.create(new OrthodoxMonkFactory(), "Мантийный монах").description();
        application.create(new CatholicMonkFactory(), "Иезуит").description();
        application.create(new AnglicanMonkFactory(), "Бенедиктинец").description();
        application.create(new BuddhistMonkFactory(), "Монах").description();
        application.create(new HinduMonkFactory(), "Саньяси").description();
    }
}
Я православный монах - Мантийный монах
Моя одежда - Мантия
Я католический монах - Иезуит
Моя одежда - Ряса с капюшоном
Я англиканский монах - Бенедиктинец
Моя одежда - Ряса
Я буддийский монах - Монах
Моя одежда - Кашая
Я индуистский монах - Саньяси
Моя одежда - Почти ничего, тепло же :)
Tóm lại, bạn có thể lưu ý rằng phương thức Factory đã sử dụng một lớp trừu tượng với một phương thức chưa được triển khai, được triển khai trong các lớp con và Nhà máy trừu tượng đã sử dụng một giao diện, trong đó việc triển khai (trong trường hợp của chúng ta là tạo một tu sĩ) xảy ra trong các lớp đã triển khai giao diện này.
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION