3 분 소요

4. 생성 패턴

생성 패턴

생성 패턴의 개요

  • 객체의 생성과 참조 과정을 추상화해 특정 객체의 생성 과정을 분리
  • 누가 언제 변경하더라도 전체 시스템에 미치는 영향을 최소화하도록 만들어줌
  • 코드의 유연성을 높일 수 있고 유지관리를 쉽게 만듬

생성 패턴의 종류

  • factory method 패턴
  • singleton 패턴
  • prototype 패턴
  • builder 패턴
  • abstract factory 패턴

factory method 패턴

객체 생성을 직접 하지 않고 누군가에게 맡기고 싶다면?
factory methos 패턴을 생각해보라

factory method 패턴의 개요

  • 객체지향 언어를 사용하면 클래스에서 다른 클래스의 새로운 객체를 만들 때 두 클래스 사이에는 의존 관계가 발생
  • 서로 간에 강한 결합을 이루게 되고 변경에 따른 영향을 받아 코드의 유연한 확장이나 변경 같은 유지보수를 어렵게 만듬
  • 필요한 객체를 클래스에서 생성하지 말고 객체 생성만 전문으로 하는 클래스를 만들어 객체 생성을 모두 생성해 해결

factory method 패턴의 단계

  • 1단계: 객체 생성을 담당하는 factory 클래스를 만들어 그곳에서 객체를 생성
  • 2단계: 객체를 생성할 수 있는 메서드를 만들어 그 메서드가 factory 클래스 역할을 하도록 함 factory 클래스는 삭제

예제 프로젝트 이해

  • 게임 서버는 게임의 종류가 늘어날 때마다 추가
  • 하나의 게임을 선택하면 게임 서버는 ‘정상 연결’ 메시지와 함께 게임명, 게임 버전, ‘게임 실행 준비 완료’ 메시지를 화면에 띄움
  • 추후에는 게임 서버도 국가별로 별도로 둘 예정이며 게임도 그 나라의 특성에 맞는 게임으로 수정할 예정

일반적인 클래스 설계

  • factory method 패턴을 사용하지 않는 경우

sw_8_14

일반적인 클래스 설계

  • 게임이 계속 추가되면 그때마다 GameServer 클래스를 수정해야함
  • 클래스 설계 원칙 중 OCP(개방 폐쇄 원칙) 위반이고 디자인 패턴의 취지와 맞지 않음
  • 객체 내부에서 다른 객체를 생성하면 객체 사이에 의존 관계가 발생
public SuperMario supermario = new SuperMario();
public Tetris tetris = new Tetris();
  • new는 컴파일 과정에서 객체를 생성하고 이를 메모리에 할당하는 역할
  • 위에서는 supermario 객체를 생성하고 tetris 객체를 생성
  • 다른 게임이 추가되면 마찬가지로 new를 사용해 객체를 생성할 것

factory method 패턴을 적용한 클래스 설계 - 1단계

sw_8_15

sw_8_16

  • 게임의 종류는 Games라는 추상 클래스의 하위 클래스에 위치
  • 새로운 게임 하나가 추가되면 GameServerFactory 클래스에서 객체를 생성하고 if 문에 추가
  • 게임의 추가/삭제에 따른 변화가 GameServer에 영향을 미치지 않음

sw_8_17

factory method 패턴을 적용한 클래스 설계 - 2단계

  • GameServer를 계속 추가할 수 있도록 KRGameServer와 JPGameServer로 GameServer를 확장
  • 국가별 특성에 맞게 약간 수정한 KRSupermario, KRTetris, JPSupermario, JPTetris를 추가해 Games를 확장

1단계와의 차이점

① GameServer 확장을 고려한 상속 구조 ② 나라별 game 증가를 고려한 상속 구조 ③ GameServerFactory 클래스가 사라짐ameServerFactory 클래스가 사라짐

sw_8_18

factory method 패턴 정리

  • 1단계: new를 사용하지 않고 객체를 생성하려면 객체를 생성할 수 있는 클래스를 만들어 모든 객체를 생성하도록 위임
  • 2단계: factory 클래스의 역할(객체 생성)을 하나의 메서드를 상위 클래스에 만들어 그 메서드가 하도록 하고 이 메서드의 구현은 하위 클래스에게 위임

singleton 패턴

객체를 오직 1개만 만들어야 한다면?
singleton 패턴을 생각해보라!

singleton 패턴의 개요

  • 의도적으로 단 하나의 객체만 생성하도록 하는 경우 사용
  • 객체가 프로그램 내에서 오직 하나만 생성되도록 보장
  • 객체를 하나만 생성해 사용하면 유용한 곳으로는 스레드 풀, 캐시, 로그 기록용 객체 등이 있음

일반적으로 작성하던 코드와 다른 점

1) 생성자가 private으로 선언 2) 객체를 생성할 때 static으로 선언

sw_8_19

singleton 패턴을 사용하지 않은 일반 프로그램

  • 실행을 해보면 객체가 3개 만들어지고 예상한 결과를 얻을 수 있지만 이는 운영체제의 병행 제어 장치의 영향 때문

sw_8_20

singleton 패턴을 사용하지 않은 일반 프로그램 - Thread 사용

  • 3명의 사용자가 원하는 음료를 내리고 완성된 것이 섞여 있고 결과가 다름
  • 목적은 객체가 오직 1개만 생성되고 다른 사용자가 그것을 참조하도록 하는 것이므로 문제가 있음

sw_8_21

singleton 패턴을 사용한 프로그램 - Thread 사용, 동기화 비사용

1) 생성자가 객체를 한 번만 생성하고 외부로부터 생성자를 호출할 수 없게 만듬 - EspressoMachine 클래스에서 생성자의 접근 제어자를 private으로 선언 2) 클래스 타입을 static(정적), private으로 선언 - 자신의 클래스 타입을 static(정적)으로 선언하고 외부에서 값을 변경하지 못하도록 private으로 선언 3) getInstance( )를 사용 - getInstance()를 만들어 사용하도록 함 - 외부에서는 EspressoMachine 클래스의 객체를 얻기 위해 getInstance()를 호출해 사용할 수밖에 없음

singleton 패턴을 사용한 프로그램 - Thread 제거, 동기화 사용

① 생성자를 private으로 선언 ② 객체 생성을 static으로 선언 ③ getInstance()를 만들어 외부에서 사용하도록 함 ④ getInstance() 메서드를 동기화

singleton 패턴을 사용한 프로그램 (객체 생성을 처음부터)

  • synchronized 사용은 두 thread가 getInstance() 메서드를 동시에 실행시키는 것을 방지
  • 동기화를 하면 속도가 떨어지는 문제가 발생하므로 public static EspressoMachine getInstance()처럼 처음부터 생성하여 해결
  • 속도가 중요하지 않다면 public synchronized static EspressoMachine getInstance()처럼 getInstance() 메서드를 동기화해 메서드의 동시 실행을 막음

singleton 패턴을 사용한 프로그램 - DCL 사용

  • DCL을 구현하는 방법은 volatile을 사용

sw_8_22

댓글남기기