목차

    싱글턴 패턴(Singleton pattern)

    소프트웨어 디자인 패턴에서 싱글턴 패턴을 따르는 클래스는, 생성자가 여러 차례 호출되더라도 실제로 생성되는 객체는 하나이고 최초 생성 이후에 호출된 생성자는 최초의 생성자가 생성한 객체를 리턴한다.

    싱글턴 패턴을 사용하는 이유

    만약 우리가 만들었던 DI 컨테이너인 요청을 할 때마다 새로운 객체를 생성한다. 요청이 엄청나게 많은 트래픽 사이트에서는 계속 객체를 생성하게 되면 메모리 낭비가 심하기 때문이다.

    스프링 컨테이너

    스프링 컨테이너는 싱글턴 패턴을 적용하지 않아도 객체 인스턴스를 싱글톤으로 관리한다. 이러한 기능 덕분에 싱글톤 패턴의 모든 단점을 해결하고 객체를 싱글톤으로 유지할 수 있다

    Spring에서 싱글톤을 사용하는 이유

    애플리케이션 컨텍스트에 의해 등록된 빈은 기본적으로 싱글톤으로 관리된다. 즉, 스프링에 여러 번 빈을 요청하더라도 매번 동일한 객체를 돌려준다는 것이다. 애플리케이션 컨텍스트가 싱글톤으로 빈을 관리하는 이유는 대규모 트래픽을 처리할 수 있도록 하기 위함이다.

    스프링은 최초에 설계될 때 부터 대규모의 엔터프라이즈 환경에서 요청을 처리할 수 있도록 고안되었다. 그리고 그에 따라 계층적으로 처리 구조(Controller, Service, Repository 등) 가 나뉘어지게 되었다.

    그런데 매번 클라이언트에서 요청이 올 때마다 각 로직을 처리하는 빈을 새로 만들어서 사용한다고 생각해보자. 요청 1번에 5개의 객체가 만들어진다고 하고, 1초에 500번 요청이 온다고 하면 초당 2500개의 새로운 객체가 생성된다. 아무리 GC의 성능이 좋아졌다 하더라도 부하가 걸리면 감당이 힘들 것이다.

    그래서 이러한 문제를 해결하고자 빈을 싱글톤 스코프로 관리하여 1개의 요청이 왔을 때 여러 쓰레드가 빈을 공유해 처리하도록 하였다.

     Spring에서 관리하는 싱글톤의 장점

    Java로 기본적인 싱글톤 패턴을 구현하고자 하면 다음과 같은 단점들이 발생한다.

    • private 생성자를 갖고 있어 상속이 불가능하다.
    • 싱글톤으로 생성되면 객체테스트가 어렵기 때문에, 테스트를 위한 객체를 새로만들어야한다.
    • 서버 환경에서는 싱글톤이 1개만 생성됨을 보장하지 못한다.
    • 전역 상태를 만들 수 있기 때문에 바람직하지 못하다.

    기본적으로 싱글톤이 멀티쓰레드 환경에서 서비스 형태의 객체로 사용되기 위해서는 내부에 상태정보를 갖지 않는 무상태(Stateless) 방식으로 만들어져야 한다. 만약 여러 쓰레드들이 동시에 상태를 접근하여 수정한다면 상당히 위험하기 때문이다.

    직접 싱글톤을 구현한다면 상당히 많은 단점들이 있겠지만, Spring 프레임워크에서 직접 싱글톤으로 객체를 관리해주므로, 우리는 더욱 객체지향적인 개발을 할 수 있게 된 것이다.

    싱글턴 방식의 주의점 ✨

    싱글톤 패턴이든, 스프링에서 객체 인스턴스를 하나만 생성해서 공유하는 상황에서 객체 인스턴스를 공유하기 때문에 객체 상태를 유지(stateful)하게 설계하면 안된다.
    1. price는 공유되는 필드이기 때문에 특정 클라이언트가 값을 변경한다.
    2. 실무에서 이런 경우를 종종 보는데, 이로인해 정말 해결하기 어려운 큰 문제들이 터진다.(몇년에 한번씩 꼭 만난다.)

    stateless(무상태)방식으로 만들어라.

    • 읽기전용 값이라면 초기화시점에서 iv에 저장해두고 공유하는 것은 문제가 없지만,
      다중 사용자의 요청을 한꺼번에 처리하는 쓰레드들이 동시에 iv를 건드리는 것은 위험하다. 따라서 stateless방식으로 만들어져야한다.
    • 파라미터, 로컬변수, 리턴값 등을 이용해, 각각의 값을 iv처럼 공유되는 영역이 아닌, 독립적인 영역에 저장하자.

    싱글톤 레지스트리

    그래서 스프링은 직접 싱글톤 형태의 오브젝트를 만들고 관리하는 기능을 제공하는데, 그것이 바로 싱글톤 레지스트리(Singleton Registry) 이다. 스프링 컨테이너는 싱글톤을 생성하고, 관리하고 공급하는 컨테이너이기도 하다. 싱글톤 레지스트리의 장점은 다음과 같다.

    • static 메소드나 private 생성자 등을 사용하지 않아 객체지향적 개발을 할 수 있다.
    • 테스트를 하기 편리하다.

    이러한 스프링에 장점을 활용하여 초기에 설정하면 사용중에는 변하지않는 읽기전용 인스턴스 변수인경우에는 서버의 성능향상을 위해 bean으로 등록하고 사용하자. 

    'Java > *****디자인패턴' 카테고리의 다른 글

    퍼사드(Facade) 패턴  (0) 2022.04.03
    빌더 패턴  (0) 2022.04.01
    싱글톤 (Singleton) 패턴  (0) 2022.04.01
    디자인 패턴  (0) 2022.03.31
    디자인 패턴 싱글톤 패턴 개념 정리  (0) 2022.03.18

    목차 돌아가기

    목차

      퍼사드(Facade)란?

      • 퍼사드 : 건물의 입구쪽 전경이라는 뜻으로 외벽에선 안이 어떻게 생겼는지 알 수없다는 의미

      퍼사드(Facade) 패턴

      복잡한 서브 시스템 의존성을 최소화하는 방법

      클라이언트가 사용해야 하는 복잡한 서브 시스템 의존성을 간단한 인터페이스로 추상화 할 수 있다.

      레거시 코드

      package com.patten.degine_patten.facade._01_before;
      
      import javax.mail.Message;
      import javax.mail.MessagingException;
      import javax.mail.Session;
      import javax.mail.Transport;
      import javax.mail.internet.InternetAddress;
      import javax.mail.internet.MimeMessage;
      import java.util.Properties;
      
      /**
       * 실제로 동작하지 않는 코드
       * 가장 간단한 이메일을 보내는 소스 코드
       * 특정한 자바가 제공하는 라이브러리에 의존성이 많은 코드 : SOLID 등 자바가 지향하는 것과 다른 느낌
       */
      public class Client {
      
          public static void main(String[] args) {
              String to = "keesun@whiteship.me";
              String from = "whiteship@whiteship.me";
              String host = "127.0.0.1";
      
              Properties properties = System.getProperties();
              properties.setProperty("mail.smtp.host", host);
      
              Session session = Session.getDefaultInstance(properties);
      
              try {
                  MimeMessage message = new MimeMessage(session);
                  message.setFrom(new InternetAddress(from));
                  message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));
                  message.setSubject("Test Mail from Java Program");
                  message.setText("message");
      
                  Transport.send(message);
              } catch (MessagingException e) {
                  e.printStackTrace();
              }
          }
      }

      해당 코드에서 java로 이메일을 보내는 코드를 작성한 것이다. 하지만 해당 코드는 너무 javax.mail 이라는 인터페이스에 의존적이다. 

      퍼사드 패턴 적용 추상화 고민하기

      • 메일을 보내는(sender) 클래스
      • 메일 설정
      • 메일 메시지

      이메일을 보내는(sender)

      센더가 의존을 담당한다. (이게 뭐하는 거지..? 조삼모사 아니냐?) 아니다. 의미가 있다. send하는 기능이 여러 곳에서 한다? 약간 util 성으로 의미가 생기게된다.

      package com.patten.degine_patten.facade._02_after;
      
      import javax.mail.Message;
      import javax.mail.MessagingException;
      import javax.mail.Session;
      import javax.mail.Transport;
      import javax.mail.internet.InternetAddress;
      import javax.mail.internet.MimeMessage;
      import java.util.Properties;
      
      public class EmailSender {
      
          private EmailSettings emailSettings;
      
          public EmailSender(EmailSettings emailSettings) {
              this.emailSettings = emailSettings;
          }
      
          /**
           * 이메일 보내는 메소드
           * @param emailMessage
           */
          public void sendEmail(EmailMessage emailMessage) {
              Properties properties = System.getProperties();
              //properties.setProperty("mail.smtp.host", host);
              properties.setProperty("mail.smtp.host", emailSettings.getHost()); //host정보는 setting에
      
              Session session = Session.getDefaultInstance(properties);
      
              try {
                  MimeMessage message = new MimeMessage(session);
                  //message.setFrom(new InternetAddress(from));
                  message.setFrom(new InternetAddress(emailMessage.getFrom())); //from 정보는 메시지에
                  //message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));
                  message.addRecipient(Message.RecipientType.TO, new InternetAddress(emailMessage.getTo())); //to 정보는 메시지에
                  message.addRecipient(Message.RecipientType.CC, new InternetAddress(emailMessage.getCc()));
                  message.setSubject(emailMessage.getSubject());
                  //message.setText("message");
                  message.setText(emailMessage.getText());
      
                  Transport.send(message);
              } catch (MessagingException e) {
                  e.printStackTrace();
              }
          }
      
      
      }

      이메일 메시지

      가장 많은 부분을 담당하는데 이메일에 필요한 내용과 관련된 정보를 담당한다.

      public class EmailMessage {
      
          private String from;
          private String to;
          private String cc;
          private String bcc;
          private String subject;
          private String text;
      
          public String getFrom() {
              return from;
          }
      
          public void setFrom(String from) {
              this.from = from;
          }
      
          public String getTo() {
              return to;
          }
      
          public void setTo(String to) {
              this.to = to;
          }
      
          public String getSubject() {
              return subject;
          }
      
          public void setSubject(String subject) {
              this.subject = subject;
          }
      
          public String getText() {
              return text;
          }
      
          public void setText(String text) {
              this.text = text;
          }
      
          public String getCc() {
              return cc;
          }
      
          public void setCc(String cc) {
              this.cc = cc;
          }
      
          public String getBcc() {
              return bcc;
          }
      
          public void setBcc(String bcc) {
              this.bcc = bcc;
          }
      }

      이메일 설정

      host같은 기본 이메일 설정을 담당한다.

      public class EmailSettings {
      
          private String host;
      
          public String getHost() {
              return host;
          }
      
          public void setHost(String host) {
              this.host = host;
          }
      }

      이메일 메인

      기존과 변화를 살펴보면 메인에서 import 했던 부분들이 사라졌다. 바로 import를 안하지만, 퍼사드에 의존하게 된다.

      public class Client {
      
          public static void main(String[] args) {
              EmailSettings emailSettings = new EmailSettings();
              emailSettings.setHost("127.0.0.1");
      
              EmailSender emailSender = new EmailSender(emailSettings);
      
              EmailMessage emailMessage = new EmailMessage();
              emailMessage.setFrom("keesun");
              emailMessage.setTo("whiteship");
              emailMessage.setCc("일남");
              emailMessage.setSubject("오징어게임");
              emailMessage.setText("밖은 더 지옥이더라고..");
      
              emailSender.sendEmail(emailMessage);
          }
      }

      퍼사드(Facade) 패턴의 장점과 단점

      복잡한 서브 시스템 의존성을 최소화하는 방법

      장점

      서브 시스템에 대한 의존성을 한곳으로 모을 수 있다. 결국 코드 읽는게 더 편해지는 것이다. 즉 추상화 정도가 강해진다.

      또한 진입 장벽이 낮다.

      단점

      퍼사드 클래스가 서브 시스템에 대한 모든 의존성을 가지게 된다.

       

      퍼사드 패턴 예제 - Spring

      패턴이 적용 되었다는 것은 보는 각도에 따라 다르게 보일 수 있다. 해당 예제는 브릿지패턴의 예제랑 같지만 보는 각도에 따라 퍼사드라고 볼 수 있다.

      package com.patten.degine_patten.facade._03_java;
      
      import org.springframework.jdbc.support.JdbcTransactionManager;
      import org.springframework.mail.MailSender;
      import org.springframework.mail.javamail.JavaMailSenderImpl;
      import org.springframework.transaction.PlatformTransactionManager;
      
      public class FacadeInSpring {
      
          public static void main(String[] args) {
              MailSender mailSender = new JavaMailSenderImpl();
      
              PlatformTransactionManager platformTransactionManager = new JdbcTransactionManager();
          }
      }

       

      'Java > *****디자인패턴' 카테고리의 다른 글

      [싱글톤 패턴] Spring에서 싱글톤을 사용하는 이유  (0) 2022.05.05
      빌더 패턴  (0) 2022.04.01
      싱글톤 (Singleton) 패턴  (0) 2022.04.01
      디자인 패턴  (0) 2022.03.31
      디자인 패턴 싱글톤 패턴 개념 정리  (0) 2022.03.18

      목차

        빌더 패턴 이란?

        동일한 프로세스를 거쳐 다양한 구성의 인스턴스를 만드는 방법

        빌더 패턴을 사용하면 객체의 생성을 깔금하고 유연하게 할 수 있다.

        Effective Java의 두번째 규칙의 제목이 바로 생성자의 인자가 많을 때는 빌더(Builder) 패턴을 이용하라

        빌더 패턴 아키텍처

        가장 중요한 부분은 Director 부분이며 클라이언트는 Director를 거친다.

        빌더 패턴 아닌 경우

        /**
        * 짧은 여행 : 짧은 여행이기 때문에 set해줄게 별로 없음
        */
        TourPlan shortTrip = new TourPlan();
        shortTrip.setTitle("오레곤 롱비치 여행");
        shortTrip.setStartDate(LocalDate.of(2021, 7, 15));
        
        /**
        * 긴 여행
        */
        TourPlan tourPlan = new TourPlan();
        tourPlan.setTitle("칸쿤 여행");
        tourPlan.setNights(2); //2박
        tourPlan.setDays(3);   //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, "체크아웃");

        문제점

        • set 해줘야 하는 값이 꼬일 수있다.
          • 2박 3일을 입력하기 위해선 setNights(2), setDays(3) 처럼 입력해야하는데 둘 중 하나를 빼 먹을 수 있다.
        • 생성자 초기 선언 할 때 너무 장황하다.
        • 그러다 보면 생성자를 조정할 수 있는데, 사용자 입장에서 어떤 생성자를 써야할지 모호해질 수 있다. 
        더보기

        초기 선언이 너무 장황한 예시

         

        빌더 패턴 구현

        Interface - TourPlanBulder

        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);
        
            /**
             * 데이터 검증을 할 수 있음.
             * nights, days 중 하나만 들어갔다던지, 근교여행인데 굳이 필요없는 값이 들어간건 아닌지
             * @return
             */
            TourPlan getPlan(); //데이터 검증
        }

        Class - DefalutTourBuilder

        /**
         * 구현체 생성
         */
        public class DefaultTourBuilder implements TourPlanBuilder {
        
            private String title;
        
            private int nights;
        
            private int days;
        
            private LocalDate startDate;
        
            private String whereToStay;
        
            private List<DetailPlan> plans;
        
            /**
             * this를 리턴한다는 것은 DefaultTourBulder가 리턴이 된다는 뜻
             * @param nights
             * @param days
             * @return
             */
            @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;
            }
        
        
            /**
             * 마지막에 인스턴스를 생성한다.
             * @return
             */
            @Override
            public TourPlan getPlan() {
                return new TourPlan(title, nights, days, startDate, whereToStay, plans);
            }
        }

        TourDirector

        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();
            }
        }

        Main

         public static void main(String[] args) {
                TourDirector director = new TourDirector(new DefaultTourBuilder());
                TourPlan tourPlan = director.cancunTrip();
                TourPlan tourPlan1 = director.longBeachTrip();
            }

        빌더 패턴 장점 & 단점

        장점

        • 빌더 패턴으로 생성자의 복잡함을 단순화 할 수 있다.
        •  

        단점

        자바와 스프링에서 찾아보는 패턴

        StringBuffer (Sync 사용)

        StringBuffer와 StringBuilder의 차이는 Sync(동기화)여부의 차이가 있다.

         public static void main(String[] args) {
                StringBuilder stringBuilder = new StringBuilder();
                String result = stringBuilder.append("whiteship").append("keesun").toString();
                System.out.println(result);
        }

         

        StringBuilder (Sync 미사용)

        Stream.Builder

        UriComponents howToStudyJava = UriComponentsBuilder.newInstance()
                    .scheme("http")
                    .host("www.whiteship.me")
                    .path("java playlist ep1")
                    .build().encode();
        System.out.println(howToStudyJava);

        lombok

        @Builder
        public class LombokExample {
        
            private String title;
        
            private int nights;
        
            private int days;
        
            public static void main(String[] args) {
                LombokExample trip = LombokExample.builder()
                        .title("여행")
                        .nights(2)
                        .days(3)
                        .build();
            }
        
        }

        Spring

           //URI를 만들어주는 Builder
           public static void main(String[] args) {
               UriComponents howToStudyJava = UriComponentsBuilder.newInstance()
                        .scheme("http")
                        .host("www.whiteship.me")
                        .path("java playlist ep1")
                        .build().encode();
                System.out.println(howToStudyJava);
            }

         

         

         

         

         

         

         

         

         

         

         

         

         

         

         

        출처

        인프런

        김영한-코딩으로 학습하는 GoF 디자인 패턴

        목차

          싱글톤 패턴이란?

          인스턴스를 오직 한개만 제공하는 클래스

          • 시스템 런타임, 환경 세팅에 대한 정보 등, 인스턴스가 여러개 일 때 문제가 생길 수 있는 경우가 있다. 인스턴스를 오직 한개만 만들어 제공하는 클래스가 필요하다.

          이른 초기화

          synchronzied

          double checked locking (복잡)

          static inner 클래스 (가장권장)

          자바와 스프링에서 찾아보는 패턴

          자바

          runtime 메서드는 자바에서 제공하는 라이브러리이며 자바에서 지금 동작하는 환경의 정보를 담고있다. 하기와 같이 Runtime은 new로 생성이 불가능하다. 즉, 싱글톤 패턴으로 구현되어있는 것을 확인할 수 있다. 

          Spring

          bean이라는 스코프에서 관리하고 있기 때문에 hello == hello2 는 true를 반환한다.

          엄밀히 따지면 싱글톤  패턴이 쓰인 것은 아니지만 싱글톤 소코프를 사용한 케이스이다.

           

           

           

           

           

          싱글톤 패턴은 어떻게 쓰이나?

          • 스프링에서 빈의 스코프 중에 하나로 싱글톤 스코프
          • 자바 Java.lang.Runtime
          • 다른 디자인 패턴(빌더, 퍼사드, 추상 팩토리 등) 구현체의 일부로 쓰이기도 한다.

           

          'Java > *****디자인패턴' 카테고리의 다른 글

          [싱글톤 패턴] Spring에서 싱글톤을 사용하는 이유  (0) 2022.05.05
          퍼사드(Facade) 패턴  (0) 2022.04.03
          빌더 패턴  (0) 2022.04.01
          디자인 패턴  (0) 2022.03.31
          디자인 패턴 싱글톤 패턴 개념 정리  (0) 2022.03.18

          객체 생성 관련 디자인 패턴

           
          패턴 종류 비고
          싱글톤 패턴 spring에서의 싱글톤
          팩토리 메서드 패턴  
          추상 팩토리 패턴  
          빌더 패턴  
          프로토 타입 패턴  

          구조 관련 디자인 패턴

          패턴 종류 비고
          어댑터 패턴  
          브릿지 패턴  
          컴포짓 패턴  
          데코레이터 패턴  
          퍼사드 패턴  
          플라이웨이트 패턴  
          프록시 패턴  

          행동 관련 디자인 패턴

          패턴 종류 비고
          책임 연쇄 패턴  
          커맨드 패턴  
          인터프리터 패턴  
          이터레이터 패턴  
          중재자 패턴  
          옵저버 패턴  
          상태 패턴  
          전략 패턴  
          템플릿 메서드 패턴  
          비지터 패턴  

          목차

            싱글톤 패턴

            • 두 가지 화면이 존재한다. 두 가지 화면은 같은 어플이다. 그럴 경우 setting을 관리하는 객체는 반드시 같은 것을 사용해야 한다는 것이다. 

             설명
            • 두 가지 페이지가 있다고 가정하자. FirstPage(우상단), SecondPage(좌하단)
            • Setting(우하단)은 darkMode 셋팅, fontSize 셋팅, 각각의 세팅 값 출력(Get), 각각의 세팅 값 변경(set)을 담당하는 Setting 클래스 이다.
            • FirstFage(우상단)은 첫 번째 페이지이며 setAndPrintSettings라는 메서드를 통해 DarkMode = true, FontSize = 15로 셋팅해 주었다.
            • SecondFage(좌하단)은 printSetting을 통해 DarkMode 여부와 FontSize를 출력한다. 
            • 결과론적으로 첫 페이지와 두번째 페이지는 셋팅값이 다르다. (첫 번째 페이지는 수정된 값, 두 번째 페이지는 기본 값)
            • 따라서 각각의 페이지는 생긴모양이 다르지만, Settings(우하단)의 세팅정보로 통일화(=싱글톤패턴) 하려고한다.
            싱글톤 패턴

            • 맨위에 생성자를 Private로 선언한다. 그렇다면 다른 클래스에서 new를 통해 Settings를 생성하지 못한다. 
            • 그 이후 Settings를 static으로 선언한다.
            • getSettings를 만든다. 만약 setting값이 null이면 new를 해주며 없다면 settings값을 바로 return 해준다.
            • new를 매번 진행하지 않므르로 결과적으로 FirstFage와 SecondFage의 DarkMode, FontSize값은 그대로 유지된다.

            정적변수 vs 동적변수

            FirstFage & SecondFage 페이지 각각 변경

            더보기

            new가 아닌 getsetting을 해줌.

            싱글톤 패턴의 단점

            • 멀티 쓰레드 환경에서 오류가 발생할 소지가 있다.
              • 안전하게 사용하는 방법 : 따로 공부하기.

             

            'Java > *****디자인패턴' 카테고리의 다른 글

            [싱글톤 패턴] Spring에서 싱글톤을 사용하는 이유  (0) 2022.05.05
            퍼사드(Facade) 패턴  (0) 2022.04.03
            빌더 패턴  (0) 2022.04.01
            싱글톤 (Singleton) 패턴  (0) 2022.04.01
            디자인 패턴  (0) 2022.03.31

            + Recent posts