JavaRush /Java Blog /Random-KO /팩토리 메소드 및 추상 팩토리 패턴

팩토리 메소드 및 추상 팩토리 패턴

Random-KO 그룹에 게시되었습니다
책 '헤드 퍼스트. 디자인 패턴”은 이러한 패턴을 다음과 같이 정의합니다. 팩토리 메소드 패턴은 객체를 생성하기 위한 인터페이스를 정의하지만 하위 클래스가 생성할 인스턴스의 클래스를 선택할 수 있도록 허용합니다. 따라서 Factory 메서드는 인스턴스화 작업을 하위 클래스에 위임합니다. 추상 팩토리 패턴은 구체적인 클래스를 지정하지 않고 상호 연관되거나 상호 의존적인 개체군을 생성하기 위한 인터페이스를 제공합니다. 이것을 더 자세히 이해하려고 노력합시다. 수도사 가 되기로 결정한 사람들에 대한 게임을 작성하기로 결정했다고 가정해 보겠습니다. (여기에는 독창적이고 특이한 것이 필요합니다) . 우리는 다음과 같이 시작할 수 있습니다. 1) Monk 클래스와 하위 클래스를 만듭니다(먼저 하나 만들어 보겠습니다).
public abstract class Monk {

    public abstract void description();
}
public class OrthodoxMonk extends Monk {
    @Override
    public void description() {
        System.out.println("Я православный монах");
    }
}
2) 그리고 물론 "수도원 서약"을 구현할 수 있는 Monastery 클래스를 만듭니다.
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();
    }
}
Я православный монах
이제 가톨릭 수도사를 만들어야 한다면 다음을 수행해야 합니다. A) 가톨릭 수도사를 위한 새 클래스를 만듭니다.
public class CatholicMonk extends Monk {
    @Override
    public void description() {
        System.out.println("Я католический монах");
    }
}
B) 수도원 클래스를 변경합니다.
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;
    }
}
따라서 새로운 유형의 승려가 등장할 때마다 새로운 클래스를 만들고 기존 클래스를 편집해야 합니다. 이 경우 변경 사항으로부터 수도원 클래스를 "캡슐화"하기 위해 수행할 수 있는 작업은 무엇입니까? 팩토리 메소드 패턴을 사용해 볼 수 있습니다. 어떻게 보일지 A) 성공회 수도사를 추가하는 것을 제외하고 수도사 클래스를 그대로 두겠습니다(가톨릭과 정교회 기독교인만이 수도원을 갖고 있는 것은 아닙니다).
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 클래스를 인터페이스로 생성하고 특정 구현에서 구현할 수도 있습니다. 이는 더 넓은 의미에서 "인터페이스"라는 단어를 의미합니다. 정의에서는 또한 하위 클래스가 자신이 생성하는 인스턴스의 클래스를 선택할 수 있도록 허용한다고 밝혔습니다 . 여기서는 하위 클래스(자식 클래스)가 이 메서드를 구현하는 것을 볼 수 있습니다(즉, 수도사 개체를 생성하는 권한이 해당 클래스에 위임됩니다). 이제 우리 프로그램을 조금 확장하여 한 종파 또는 다른 종파에 다양한 승려가 있을 가능성을 소개해 보겠습니다. 예를 들어, 정교회에서는 수도원과 수도원에 대한 정교회의 입장 (2017년 11월 29일부터 12월 2일까지 러시아 정교회 주교 협의회에서 채택됨)을 바탕으로 두 가지 유형의 승려가 있다는 결론을 내릴 수 있습니다. : - 더 작은 스키마(맨틀). - 스키마(훌륭한 스키마). "준비 단계"도 있지만 사람들은 수도원 서약을 하지 않기 때문에 승려(Trudnik, Novice 및 Ryasophor 또는 Monk)로 간주되지 않습니다. 따라서 우리는 이를 고려하지 않습니다. 이 경우 무엇을 얻을 수 있습니까? A) Factory 메소드를 사용하는 Monastery 클래스(단순화하기 위해 지금은 정통 수도원에 중점을 두겠습니다) :
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);
    }
}
B) 수도사 클래스를 수정해 보겠습니다.
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);
    }
}
C) 코드를 확인해 보겠습니다.
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 패턴을 사용할 시간입니다. 수도사들이 있으니 이제 그들에게 옷과 묵주 등을 만들어 줄 수 있습니다. 의복부터 시작하겠습니다. 즉, 처음의 정의로 돌아가면 의복은 상호 연결되거나 상호 의존적인 객체의 계열이 될 것입니다 . 각 유형의 스님이 서로 다른 예복을 가지고 있다는 문제부터 시작해 보겠습니다. 불교도 추가하면 완전히 달라집니다. :) 이를 위해 필요한 옷을 구현하는 팩토리 인터페이스를 만들 수 있습니다. 그러므로 A) 옷을 만드는 공장을 만든다.
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();
    }
}
B) 의복 클래스를 만듭니다(간결하게 하기 위해 승려 의복의 핵심 요소를 다루겠습니다. 자세히 설명하지 않겠습니다).
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("Кашая");
    }
}
C) 다음으로 승려의 클래스를 변경하여 옷을 입도록 합니다.
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) 수도원 클래스에는 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);
    }
}
D) 결과를 확인합니다.
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();
    }
}
Я православный монах - Мантийный монах
Моя одежда - Мантия
Я католический монах - Иезуит
Моя одежда - Ряса с капюшоном
Я англиканский монах - Бенедиктинец
Моя одежда - Ряса
Я буддийский монах - Монах
Моя одежда - Кашая
옷을 만드는 공장이 잘 돌아가기 시작했어요. 이제 성공적인 기도를 위한 수도사용 장비(묵주 등) 생산을 공장에 추가할 수 있습니다. 하지만 질문은 여전히 ​​남아 있습니다. 두 패턴을 함께 사용할 수 있습니까? 물론 가능합니다 :) 프로젝트의 최종 버전을 만들고 힌두 수도사를 추가해 보겠습니다. A) 이제 공장에서는 "스타 팩토리"처럼 들리는 수도사를 만듭니다 .
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) Monastery 클래스 + Monastery 클래스의 구체적인 구현은 필요하지 않으며 공장에서 구현됩니다. (반대로 공장을 그대로 두고 제거할 수 있지만 본질적으로 공장 대신에 있을 뿐입니다. 이 경우 수도원은 추상 클래스가 아닌 인터페이스로 만들어져야 합니다. 그리고 애플리케이션 클래스를 추가합니다.
public class Application {

    public Monk create(MonkFactory monkFactory, String type) {
        Monk monk = monkFactory.createMonk(type);
        monk.prepare(monkFactory);
        return monk;
    }
}
B) 수도사는 이제 다음을 포함합니다.
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());
    }
}
D) 그리고 확인해 봅시다:
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 메소드는 하위 클래스에서 구현된 구현되지 않은 메소드가 있는 추상 클래스를 사용했으며 Abstract Factory는 구현(우리의 경우 Monk 생성)이 구현된 클래스에서 발생한 인터페이스를 사용했다는 점을 알 수 있습니다. 이 인터페이스.
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION