JavaRush /وبلاگ جاوا /Random-FA /روش کارخانه و الگوهای انتزاعی کارخانه

روش کارخانه و الگوهای انتزاعی کارخانه

در گروه منتشر شد
در کتاب «اول سر. Design Patterns” این الگوها را به صورت زیر تعریف می کند: الگوی Factory Method رابطی را برای ایجاد یک شی تعریف می کند، اما به کلاس های فرعی اجازه می دهد تا کلاس نمونه ای را که باید ایجاد شود را انتخاب کنند. بنابراین، روش Factory عملیات نمونه سازی را به زیر کلاس ها واگذار می کند. الگوی Abstract Factory یک رابط برای ایجاد خانواده های اشیاء مرتبط یا وابسته به هم بدون مشخص کردن کلاس های مشخص آنها فراهم می کند. بیایید سعی کنیم این را با جزئیات بیشتری درک کنیم. فرض کنید تصمیم دارید یک بازی در مورد افرادی بنویسید که تصمیم می‌گیرند... (در اینجا به چیزی بدیع و غیرعادی نیاز دارید) راهبان شوند. می توانیم با موارد زیر شروع کنیم. 1) یک کلاس Monk و کلاس های کودک ایجاد کنید (بیایید ابتدا یکی را ایجاد کنیم):
public abstract class Monk {

    public abstract void description();
}
public class OrthodoxMonk extends Monk {
    @Override
    public void description() {
        System.out.println("Я православный монах");
    }
}
2) و البته، یک کلاس صومعه ایجاد کنید، که در آن می توانید "نذر صومعه" را اجرا کنید:
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;
    }
}
خوب، بیایید نتیجه را بررسی کنیم:
public class Main {
    public static void main(String[] args) {
        Monastery monastery = new Monastery();
        monastery.createMonk("ORTODOX");
        monastery.getMonk().description();
    }
}
Я православный монах
حال اگر نیاز به ایجاد... یک راهب کاتولیک دارید، باید الف) یک کلاس جدید برای یک راهب کاتولیک ایجاد کنید:
public class CatholicMonk extends Monk {
    @Override
    public void description() {
        System.out.println("Я католический монах");
    }
}
ب) تغییراتی در کلاس صومعه ایجاد کنید:
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;
    }
}
و بنابراین هر بار که انواع جدیدی از راهبان معرفی می شوند، باید یک کلاس جدید ایجاد کنید و کلاس موجود را ویرایش کنید. در این مورد چه کاری می توان کرد تا به نوعی کلاس صومعه خود را از تغییرات "محفظه" کنیم. می توانید از الگوی Factory Method استفاده کنید. چگونه به نظر می رسد الف) بیایید طبقه راهبان را همانطور که هست رها کنیم، جز اینکه شاید یک راهب انگلیسی را اضافه کنیم (نه تنها کاتولیک ها و مسیحیان ارتدوکس رهبانیت دارند):
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("Я англиканский монах");
    }
}
ب) کلاس monastery را به صورت زیر تغییر می دهیم (آن و روش آن را انتزاعی می کنیم). در اینجا ما فقط از روش Factory استفاده می کنیم:
public abstract class Monastery {
    protected abstract Monk createMonk();
}
و کلاس های فرزند را با پیاده سازی متد ایجاد کنید:
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();
    }
}
ب) بیایید کد را بررسی کنیم
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();
    }
}
Я православный монах
Я католический монах
Я англиканский монах
آن ها همانطور که اکنون می بینیم، هنگام افزودن انواع جدید راهبان، نیازی به تغییر کلاس های موجود نخواهد بود، اما فقط در صورت لزوم، کلاس های جدید را اضافه کنید (کلاس یک صومعه و راهب خاص). شاید یکی قبلاً متوجه شده باشد که متد توصیفی که از همان ابتدا در کلاس Monk بود Factory نیز بود :) در تعریف متد کارخانه می گفت که الگوی ما رابط ایجاد یک شی را تعریف می کند اما ما هیچ چیزی ایجاد نکردیم. اینترفیس‌ها، اگرچه می‌توانیم کلاس Monastery را به عنوان یک رابط ایجاد کنیم و آن را در پیاده‌سازی‌های خاص پیاده‌سازی کنیم. این به کلمه "رابط" در معنای گسترده تر اشاره دارد. این تعریف همچنین می‌گوید که به زیر کلاس‌ها اجازه می‌دهد تا کلاس نمونه‌ای را که ایجاد می‌کنند انتخاب کنند . در اینجا فقط می بینیم که زیر کلاس ها (کلاس های کودک) این روش را پیاده سازی می کنند (یعنی این قدرت ها برای ایجاد اشیاء راهب به آنها واگذار می شود). حالا بیایید برنامه خود را کمی گسترش دهیم، احتمال وجود راهبان مختلف در یک فرقه یا فرقه دیگر را معرفی کنیم. به عنوان مثال، در ارتدکس، بر اساس موضع کلیسای ارتدکس در مورد صومعه ها و صومعه ها (که در شورای اسقف های کلیسای ارتدکس روسیه در 29 نوامبر - 2 دسامبر 2017 به تصویب رسید)، می توان نتیجه گرفت که 2 نوع راهب وجود دارد. : - طرحواره کوچکتر (مانتو). - طرحواره (طرحواره بزرگ). "مراحل آماده سازی" نیز وجود دارد، اما مردم راهبان (Trudnik، Novice و Ryasophor یا Monk) در نظر گرفته نمی شوند، زیرا آنها نذر رهبانی نمی کنند. بنابراین ما آنها را در نظر نمی گیریم. در این مورد چه چیزی به دست می آوریم: الف) کلاس صومعه (برای ساده کردن، بیایید فعلاً روی رهبانیت ارتدکس تمرکز کنیم) با روش Factory :
public abstract class Monastery {
    protected abstract Monk createMonk(String type);
}
و یک صومعه خاص
public class OrthodoxMonastery extends Monastery {

    @Override
    protected Monk createMonk(String type) {
        return new OrthodoxMonk(type);
    }
}
ب) بیایید کلاس راهبان را درست کنیم:
public abstract class Monk {
    String kind;

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

    public abstract void description();
}
و کلاس کودک:
public class OrthodoxMonk extends Monk {
    public OrthodoxMonk(String kind) {
        super(kind);
    }

    @Override
    public void description() {
        System.out.println("Я православный монах - " + kind);
    }
}
ج) بیایید کد خود را بررسی کنیم:
public class Main {
    public static void main(String[] args) {
        Monastery monastery = new OrthodoxMonastery();
        monastery.createMonk("Мантийный монах").description();
        monastery.createMonk("Великосхимник").description();
    }
}
Я православный монах - Мантийный монах
Я православный монах — Великосхимник
بنابراین، با استفاده از الگوی Factory Method، به این نتیجه رسیدیم که نیازی به تغییر کلاس های نوشته شده قبلی نداریم، اما همچنین هنگام گسترش تصاویر (انواع) راهبان، حداقل تغییرات در کد مورد نیاز است. بیایید همه دستورات و جماعت راهبان کاتولیک را بررسی و اضافه کنیم :) اما بهتر است روی 3 مورد از معروف ترین آنها تمرکز کنیم، زیرا بیش از 100 مورد از آنها وجود دارد: 1) بندیکتین 2) یسوعی 3) فرانسیسکن برای انجام این کار، مانند قبل با راهب ارتدکس، ما باید یک کلاس خاص از راهب کاتولیک را پیاده سازی کنیم:
public class CatholicMonk extends Monk {
    public CatholicMonk(String kind) {
        super(kind);
    }

    @Override
    public void description() {
        System.out.println("Я католический монах - " + kind);
    }
}
و کلاس صومعه:
public class CatholicMonastery extends Monastery {

    @Override
    protected Monk createMonk(String type) {
        return new CatholicMonk(type);
    }
}
و کد را بررسی کنید:
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();
    }
}
Я православный монах - Мантийный монах
Я православный монах - Великосхимник
Я католический монах - Бенедиктинец
Я католический монах - Иезуит
Я католический монах - Францисканец
بیایید با این الگو تمام کنیم. همه این نوع راهبان را می‌توان از قبل به کلاس E-num اضافه کرد، اما برای ساده‌سازی کد، بدون آن کار می‌کنیم. زمان الگوی Abstract Factory فرا رسیده است. ما راهبان داریم، حالا می‌توانیم برایشان لباس، تسبیح و غیره درست کنیم. بیایید با لباس شروع کنیم، یعنی اگر به تعریف خود در ابتدا برگردیم، لباس به خانواده ای از اشیاء به هم پیوسته یا وابسته به هم تبدیل می شود . بیایید با این مشکل شروع کنیم که هر نوع راهب لباس های متفاوتی دارد. اگر بودایی را اضافه کنیم، آنها کاملاً متفاوت خواهند بود :) برای انجام این کار، می توانیم یک رابط کارخانه ایجاد کنیم که اجرای آن لباس های لازم را ایجاد می کند. بنابراین الف) ما یک کارخانه برای تولید لباس ایجاد می کنیم
public interface MonkFactory {
    Clothing createClothing();
}
و اجرای آن
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();
    }
}
خب، راهبان بودایی را فراموش نکنیم :)
public class BuddhistMonkFactory implements MonkFactory {

    @Override
    public Clothing createClothing() {
        return new BuddhistClothing();
    }
}
ب) یک کلاس لباس ایجاد کنید (برای ساده کردن، بیایید عنصر کلیدی لباس راهبان را در نظر بگیریم، به جزئیات نخواهیم پرداخت):
public abstract class Clothing {
    private String name;

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

    public String getName() {
        return name;
    }
}
و کلاس های کودک
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("Кашая");
    }
}
ج) بعد طبقات راهبان را عوض می کنیم تا لباس داشته باشند:
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());
    }
}
د) کلاس monastery حاوی متد Factory ما است
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);
}
پیاده سازی های ما تغییر نکرده است
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);
    }
}
د) نتیجه را بررسی کنید:
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();
    }
}
Я православный монах - Мантийный монах
Моя одежда - Мантия
Я католический монах - Иезуит
Моя одежда - Ряса с капюшоном
Я англиканский монах - Бенедиктинец
Моя одежда - Ряса
Я буддийский монах - Монах
Моя одежда - Кашая
کارخانه تولید لباس به خوبی شروع به کار کرده است. اکنون می توانید تولید تجهیزات راهبان برای دعای موفقیت آمیز (تسبیح و ...) را به کارخانه اضافه کنید. اما این سوال همچنان باقی است که آیا می توان از 2 الگو با هم استفاده کرد؟ مطمئناً می توانید :) بیایید سعی کنیم نسخه نهایی پروژه خود را بسازیم و یک راهب هندو اضافه کنیم: الف) کارخانه ها اکنون صداهای راهبان را مانند "کارخانه ستاره" ایجاد می کنند :
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();
    }
}
ب) کلاس صومعه + اجرای بتنی کلاس Monastery نیازی نیست، آنها توسط کارخانه اجرا می شوند (برعکس، ما می توانیم آنها را رها کنیم و کارخانه ها را حذف کنیم، اما در اصل آنها به سادگی به جای کارخانه ها خواهند بود، فقط در در این صورت، صومعه باید به عنوان یک رابط، و نه کلاس انتزاعی، ساخته شود. و کلاس برنامه را اضافه کنید:
public class Application {

    public Monk create(MonkFactory monkFactory, String type) {
        Monk monk = monkFactory.createMonk(type);
        monk.prepare(monkFactory);
        return monk;
    }
}
ب) راهبان در حال حاضر شامل
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);
}
شامل یک روش کارخانه ای در پیاده سازی است که با استفاده از یک کارخانه پیاده سازی می شود:
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());
    }
}
د) و بیایید بررسی کنیم:
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();
    }
}
Я православный монах - Мантийный монах
Моя одежда - Мантия
Я католический монах - Иезуит
Моя одежда - Ряса с капюшоном
Я англиканский монах - Бенедиктинец
Моя одежда - Ряса
Я буддийский монах - Монах
Моя одежда - Кашая
Я индуистский монах - Саньяси
Моя одежда - Почти ничего, тепло же :)
در پایان، می‌توانید توجه داشته باشید که Factory Method از یک کلاس انتزاعی با یک متد اجرا نشده استفاده می‌کند که در زیر کلاس‌ها پیاده‌سازی شده است، و Abstract Factory از یک رابط استفاده می‌کند، که در آن پیاده‌سازی (در مورد ما، ایجاد راهب) در کلاس‌هایی رخ می‌دهد که این را پیاده‌سازی می‌کنند. رابط.
نظرات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION