設計モードの作成(2)-抽象ファクトリモード、コンストラクタモード、プロトタイプモード


抽象ファクトリモード


複数の相互関連オブジェクトを作成するインタフェース
クライアント・モード
クライアントコード(ファクトリでインスタンスを作成)をインタフェースに基づいて
public class WhiteshipFactory extends DefaultShipFactory {

    @Override
    public Ship createShip() {
        Ship ship = new Whiteship();
        ship.setAnchor(new WhiteAnchor());
        ship.setWheel(new WhiteWheel());
        return ship;
    }
}
クライアントのコード、具体的なコードに依存します.(new WhiteAnchor()) , new WhiteWheel())
WhiteAnchor、WhiteWheelではなくスタイルを変えたい場合は、そのたびにコードが変わります.
これらの部分を変更せずに新製品を追加する方法の問題を解決できます.

public interface Anchor {}
public interface Wheel {}

public interface ShipPartsFactory {// 추상팩토리

    Anchor createAnchor();
    Wheel createWheel(); 
    
    
}

public class WhiteshipPartsFactory implements ShipPartsFactory { 
// 추상팩토리의 구체적인 팩토리

    @Override
    public Anchor createAnchor() {
        return new WhiteAnchor();
    }

    @Override
    public Wheel createWheel() {
        return new WhiteWheel();
    }
}
public class WhiteshipFactory extends DefaultShipFactory { 
//클라이언트

    private ShipPartsFactory shipPartsFactory;

    public WhiteshipFactory(ShipPartsFactory shipPartsFactory) {
        this.shipPartsFactory = shipPartsFactory;
    }

    @Override
    public Ship createShip() {
        Ship ship = new Whiteship();
        ship.setAnchor(shipPartsFactory.createAnchor());
        ship.setWheel(shipPartsFactory.createWheel());
        return ship;
    }
}
理想的な状態でpro製品が追加されます.昔なら.
ship.これをsetAnchor(新しいWhiteAnchorPro)に設定する必要があります.
public class WhiteAnchorPro implements Anchor{
}
public class WhiteWheelPro implements Wheel {
}

public class WhitePartsProFactory implements ShipPartsFactory {
    @Override
    public Anchor createAnchor() {
        return new WhiteAnchorPro();
    }

    @Override
    public Wheel createWheel() {
        return new WhiteWheelPro();
    }
}
コードを変更せずに、次のようにインタフェースとクラスを追加するだけです.
  public static void main(String[] args) {
        ShipFactory shipFactory = new WhiteshipFactory(new WhiteshipPartsFactory());
        Ship ship = shipFactory.createShip();
        System.out.println(ship.getAnchor().getClass());
        System.out.println(ship.getWheel().getClass());
    }
WhiteAnchor、WhiteWheelは中に入ることを確認できます.
抽象工場メソッドモデルとの違いは?
ファクトリメソッド-抽象オブジェクトの作成プロセス、特定のタイプのインスタンスを非表示および抽象化します.
工場を提供する.
工場化の実現方法に重点を置く
目的は、特定のオブジェクトの作成プロセスをサブクラスまたは特定のクラスに移動することです.
≪抽象ファクトリ|Absolute Factory|emdw≫:抽象オブジェクトの作成プロセス.クライアントの観点から、ファクトリを介して抽象的なインタフェースのみを使用できるようにします.
工場の使い方に重点を置く
特定のクラスに依存せずに複数のオブジェクトを作成できるようにすることを目的としています.

ビルダーモード

public static void main(String[] args){
      TourPlan shortTrip = new TourPlan();
        shortTrip.setTitle("영주여행 ");
        shortTrip.setStartDate(LocalDate.of(2021, 11, 06));
        
       TourPlan tourPlan = new TourPlan();
        tourPlan.setTitle("칸쿤 여행");
        tourPlan.setNights(2);
        tourPlan.setDays(3);
        tourPlan.setStartDate(LocalDate.of(2020, 12, 9));
        tourPlan.setWhereToStay("리조트");
        tourPlan.addPlan(0, "체크인 이후 짐풀기");
        tourPlan.addPlan(0, "저녁 식사");
        tourPlan.addPlan(1, "조식 부페에서 식사");
        tourPlan.addPlan(1, "해변가 산책");
        tourPlan.addPlan(1, "점심은 수영장 근처 음식점에서 먹기");
        tourPlan.addPlan(1, "리조트 수영장에서 놀기");
        tourPlan.addPlan(1, "저녁은 BBQ 식당에서 스테이크");
        tourPlan.addPlan(2, "조식 부페에서 식사");
        tourPlan.addPlan(2, "체크아웃"); 
        
        
}
次の例では、インスタンスが不安定になる可能性があります.
ジェネレータを作成する必要がある場合、多くの偽数が発生し、冗長になる可能性があります.
コンストラクタモードは、複雑なオブジェクトを作成するプロセスとは独立して、プロセスによってさまざまな構成インスタンスを作成する方法です.
public interface TourPlanBuilder {

    TourPlanBuilder nightsAndDays(int nights, int days);
    TourPlanBuilder title(String title);
    TourPlanBuilder startDate(LocalDate localDate);
    TourPlanBuilder whereToStay(String whereToStay);
    TourPlanBuilder addPlan(int day, String plan);
    TourPlan getPlan();

}
ビルドのリターンカータイプでいろいろなものを作っていて、以下のようになっています
コンストラクタによるメソッドフィルタリング
クライアントがnightsAndDaysというメソッドを呼び出した場合、TourPlanBuilderタイプのインスタンスが受信されます.
では、中で提供されている別の方法を使用します.
getPlanに出会うまで
getPlanでは、インスタンスのステータスを検証し、不安定であるかどうかを検証することもできます.
public class DefaultTourBuilder implements TourPlanBuilder {

    private String title;
    private int nights;
    private int days;
    private LocalDate startDate;
    private String whereToStay;
    private List<DetailPlan> plans;

    @Override
    public TourPlanBuilder nightsAndDays(int nights, int days) {
        this.nights = nights;
        this.days = days;
        return this;
    }

    @Override
    public TourPlanBuilder title(String title) {
        this.title = title;
        return this;
    }

    @Override
    public TourPlanBuilder startDate(LocalDate startDate) {
        this.startDate = startDate;
        return this;
    }

    @Override
    public TourPlanBuilder whereToStay(String whereToStay) {
        this.whereToStay = whereToStay;
        return this;
    }

    @Override
    public TourPlanBuilder addPlan(int day, String plan) {
        if (this.plans == null) {
            this.plans = new ArrayList<>();
        }

        this.plans.add(new DetailPlan(day, plan));
        return this;
    }

    @Override
    public TourPlan getPlan() {
        return new TourPlan(title, nights, days, startDate, whereToStay, plans);
    }
}
//클라이언트쪽 코드 
 public static void main(String[] args) {
        TourPlanBuilder builder = new DefaultTourBuilder();
        
        builder.title("칸쿤여행")
        .nightsAndDays(2,3)
        .startDate(LocalDate.of(2021,11,6))
        .whereToStay("리조트")
        .addPlan(0,"체크인하고 짐풀기")
        .getPlan();
        
        TourPlan longBeachTrip = builder.title("롱비치")
        .startDate(LocalDate.of(2021,06,15))
        .getPlan();
        
        
    }
コンストラクタモードがない場合は、冗長なジェネレータと多くの空の値を含むジェネレータが表示される場合があります.
上記コードをコントローラとして個別に削除することもできます.
public class TourDirector {

    private TourPlanBuilder tourPlanBuilder;

    public TourDirector(TourPlanBuilder tourPlanBuilder) {
        this.tourPlanBuilder = tourPlanBuilder;
    }

    public TourPlan cancunTrip() {
        return tourPlanBuilder.title("칸쿤 여행")
                .nightsAndDays(2, 3)
                .startDate(LocalDate.of(2020, 12, 9))
                .whereToStay("리조트")
                .addPlan(0, "체크인하고 짐 풀기")
                .addPlan(0, "저녁 식사")
                .getPlan();
    }

    public TourPlan longBeachTrip() {
        return tourPlanBuilder.title("롱비치")
                .startDate(LocalDate.of(2021, 7, 15))
                .getPlan();
    }
}
コントローラを作成します.
  public static void main(String[] args) {
        TourDirector director = new TourDirector(new DefaultTourBuilder());
        TourPlan tourPlan = director.cancunTrip();
        TourPlan tourPlan1 = director.longBeachTrip();
    }

コンストラクタモードの利点

  • 複雑なオブジェクトを順番に作成できるようにする
    =>コンストラクタモードは1つしか作成されていませんが、コンストラクタモードにコンストラクタモードを追加することもできます.

  • 複雑なオブジェクトを作成する具体的な手順を非表示にできます.
    =>コントローラで非表示にします.

  • 同じプロシージャで異なるオブジェクトを作成できます.
    =>TourPlanタイプですが、TourPlanのサブタイプの内容でも構いません.
    たとえばカンクン旅行ではVIPならではの旅行のオブジェクトを作成できます.

  • 不完全なオブジェクトの使用を防ぐことができます.
    =>getPlan()でオブジェクトを検証することもできます
  • 短所

  • TourPlanを作成するには、まずコントローラまたはコンストラクタを作成する必要があります.
    =>オブジェクトをさらに作成する必要があるため、欠点になる可能性があります.

  • ほとんどのデザインパターンはありますが、構造が複雑になります.
    =>適用前とは異なり、モードを適用した後はコンストラクタ、コントローラを通過する必要があります.
  • コンストラクタモードの適用例
    StringBuilder
     public static void main(String[] args) {
            StringBuilder stringBuilder = new StringBuilder();
            String result = stringBuilder.append("yj").append("youngjin").toString();
            System.out.println(result);
        }
    Stream
     public static void main(String[] args) {
            Stream<String> names = Stream.<String>builder().add("yj").add("youngjin").build();
            names.forEach(System.out::println);
        }
    等~~builderで終わる名前をコンストラクタモードとする

    プロトタイプモード


    既存のインスタンスをコピーして新しいインスタンスを作成します.
    コピー機能を持つ既存のインスタンスをプロトタイプとして使用して新しいインスタンスを作成できます.
    public class GithubRepository {
    
        private String user;
        private String name;
        public String getUser() {
            return user;
        }
        public void setUser(String user) {
            this.user = user;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
    }
    public class GithubIssue {
    
        private int id;
        private String title;
        private GithubRepository repository;
        public GithubIssue(GithubRepository repository) {
            this.repository = repository;
        }
    
        public int getId() {
            return id;
        }
        public void setId(int id) {
            this.id = id;
        }
        public String getTitle() {
            return title;
        }
        public void setTitle(String title) {
            this.title = title;
        }
        public GithubRepository getRepository() {
            return repository;
        }
        public String getUrl() {
            return String.format("https://github.com/%s/%s/issues/%d",
                    repository.getUser(),
                    repository.getName(),
                    this.getId());
        }
    }
    
    
      public static void main(String[] args) {
            GithubRepository repository = new GithubRepository();
            repository.setUser("whiteship");
            repository.setName("live-study");
    
            GithubIssue githubIssue = new GithubIssue(repository);
            githubIssue.setId(1);
            githubIssue.setTitle("1주차 과제: JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가.");
    
            String url = githubIssue.getUrl();
            System.out.println(url);
            
           
        }
    GithubIssue githubIssue2 = githubIssue.clone(); //이런식으로 
    사용하고싶다.34의 이슈가 나올때 
    githubIssue.setId(2);
    githubIssue.setTitle("2주차 과제:");
    クローンが作成されたとします.
    GithubIssue clone = githubIssue.clone();
    clone == githubIssue => false
    clone.equals(githubIssue) => true
    Objectのclone()メソッドが使用できない理由は
    オブジェクトはclone()のアクセス制御者によって保護されるためです.
    public class GithubIssue implements Cloneable {
    
        private int id;
        private String title;
        private GithubRepository repository;
        public GithubIssue(GithubRepository repository) {
            this.repository = repository;
        }
        public int getId() {
            return id;
        }
        public void setId(int id) {
            this.id = id;
        }
        public String getTitle() {
            return title;
        }
        public void setTitle(String title) {
            this.title = title;
        }
        public GithubRepository getRepository() {
            return repository;
        }
    
        public String getUrl() {
            return String.format("https://github.com/%s/%s/issues/%d",
                    repository.getUser(),
                    repository.getName(),
                    this.getId());
        }
    
        @Override
        protected Object clone() throws CloneNotSupportedException { 
        //깊은복제가 되게끔구현 
            GithubRepository repository = new GithubRepository();
            repository.setUser(this.repository.getUser());
            repository.setName(this.repository.getName());
    
            GithubIssue githubIssue = new GithubIssue(repository);
            githubIssue.setId(this.id);
            githubIssue.setTitle(this.title);
    
            return githubIssue;
        }
    
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            GithubIssue that = (GithubIssue) o;
            return id == that.id && Objects.equals(title, that.title) && Objects.equals(repository, that.repository);
        }
    
        @Override
        public int hashCode() {
            return Objects.hash(id, title, repository);
        }
    }

    Javaが提供するクローン基本機能(この場合は浅いレプリケーション)も使用できます.
    クローンの基本機能を使用する場合
    GithubIssue clone = (GIthubIssue) githubIssue.clone();
    クローンを使用するメリットは
    新しい話題が出るたびに、重複するコードがdbを通過したり、ネットワークを通じてリソースを大量に消費したりすると、このコードは重複しないので、利益を得ることができます.
    JAvaが提供するクローンは「浅いコピー」です
    https://velog.io/@dudwls0505/clone-%EB%A6%AC%ED%94%8C%EB%A0%89%EC%85%98
    クローンに困惑している場合は、この文書を参照してください.
    プロトタイプの利点

  • 複雑なオブジェクトを作成するプロセスを非表示にできます.
    =>cloneメソッドで

  • 既存のオブジェクトをコピーするプロセスは、新しいインスタンスを作成するよりもコスト効率が高い場合があります.

  • 抽象タイプを復元できます.
  • 短所
  • 複雑なオブジェクトを作成するプロセス自体が複雑である可能性があります.(ループ参照がある場合、特にそうです.)
  • プロトコル・モードの使用例
    Javaコレクション
      public static void main(String[] args) {
            Student keesun = new Student("keesun");
            Student whiteship = new Student("whiteship");
            List<Student> students = new ArrayList<>();
            students.add(keesun);
            students.add(whiteship);
    
            List<Student> clone = new ArrayList<>(students);
            System.out.println(clone);
        }
    リストはクローンをサポートしておらず、ArrayListはクローンをサポートしているので、どのように書き込むか(厳密にはプロトコルモードは適用されません)
      public static void main(String[] args) {
            GithubRepository repository = new GithubRepository();
            repository.setUser("whiteship");
            repository.setName("live-study");
    
            GithubIssue githubIssue = new GithubIssue(repository);
            githubIssue.setId(1);
            githubIssue.setTitle("1주차 과제: JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가.");
    
            ModelMapper modelMapper = new ModelMapper();
            GithubIssueData githubIssueData = modelMapper.map(githubIssue, GithubIssueData.class);
            System.out.println(githubIssueData);
        }
    apiを作成したり、応答タイプやリクエストの本文をグループ化したりすると、modelmapperが通常表示されます.
    オブジェクトに含まれるやつをreplicationにマッピングして入れます.
    関連項目:https://www.inflearn.com/course/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4/dashboard