[Design Pattern] 디자인 패턴

DEINGVELOP·2023년 2월 2일
0

CS | Design Pattern

목록 보기
2/2

디자인 패턴이란?

: 기존 환경 내에서 반복적으로 일어나는 문제들을 어떻게 풀어나갈 것인가에 대한 일종의 솔루션

  • 설계할 때 발생했던 문제점들을 객체 간의 상호관계 등을 이용하여 해결할 수 있도록 하나의 '규약' 형태로 만들어놓은 것

  • GoF의 디자인 패턴(디자인 패턴계의 교과서)에서는 객체지향적 디자인 패턴의 카테고리를 3가지로 분류

    • 생성 패턴 (Creational Pattern)
    • 구조 패턴 (Structural Pattern)
    • 행동 패턴 (Behavioral Pattern)

1. 생성 패턴

: 객체의 생성에 관련된 패턴으로, 객체의 생성절차를 추상화하는 패턴

  • 인스턴스를 만드는 절차를 추상화하는 패턴

  • 시스템으로부터 객체의 생성/합성 방법을 분리해내기 위함

생성패턴의 특징

  • 시스템이 어떤 구체 클래스를 사용하는지, 인스턴스들이 어떻게 만들어지고 어떻게 합성되는지에 대한 정보를 완전히 가려줌(캡슐화)

  • 무엇이 생성되나요? → 알 수 없음

  • 어떻게 생성되나요? → 알 수 없음

  • 언제 생성되나요? → 알 수 없음

  • 누가 이걸 생성하나요? → 알 수 없음


1-1. 싱글톤 패턴(Singleton Pattern)

: 하나의 클래스에 오직 하나의 인스턴스만 가지는 패턴

  • 하나의 클래스를 기반으로 단 하나의 인스턴스를 만들어, 이를 기반으로 로직을 만드는 데에 쓰임

  • 생성자가 여러 차례 호출되더라도 실제로 생성되는 객체는 하나이고 최초 생성 이후에 호출된 생성자는 최초의 생성자가 생성한 객체를 리턴함

  • 하나의 인스턴스를 만들어놓고, 해당 인스턴스를 다른 모듈들이 공유하여 사용하기 때문에 인스턴스 생성 비용이 감소됨

  • 모듈 간의 결합을 강하게 만든다는 단점이 있음

    💡 이러한 모듈 간의 결합을 조금 느슨하게 하기 위해 의존성 주입(Dependency Injection)이라는 개념을 사용할 수 있다.

사용 예시

  • 보통 데이터베이스 연결 모듈(DBCP, DataBase Connection Pool)에 많이 사용함
    (DB 연결 과정이 부하가 크고, 한 번 연결된 객체를 계속 사용해야 하기 때문)

  • 스프링 컨테이너도 객체를 싱글톤으로 관리함

구현

Java에서의 싱글톤 구현

class Singleton {
	private static class singleInstanceHolder {
    	private static final Singleton INSTANCE = new Singleton();
    }
    public static Singleton getInstance() {
    	return singleInstanceHolder.INSTANCE;
    }
}

public class HelloWorld {
	public static void main(String[] args) {
    	Singleton a = Singleton.getInstance();
        Singleton b = Singleton.getInstance();
        System.out.println(a.hashCode());
        System.out.println(b.hashCode());
        if (a == b) {
        	System.out.println(true);
        }
    }
}

JDBC에서 싱글톤을 활용하여 DB 연결하기

// 데이터베이스와 연결과 끊어주기위한 클래스

import java.sql.Connection; 
import java.sql.DriverManager;
import java.sql.SQLException;


public class DBConn {

       private static Connection dbConn;
       public static Connection getConnection() throws SQLException, ClassNotFoundException{
             if (dbConn == null){
                   //dbConn이 null이면, 연결된 것이 없으니 연결해야한다.
                  String url = "jdbc:oracle:thin:@127.0.0.1:1521:xe" ;
                  String user = "hr";
                  String pass = "12345";
                  Class. forName("oracle.jdbc.driver.OracleDriver");
                   dbConn = DriverManager.getConnection(url, user, pass);
            }
             return dbConn ;
      }
       //db와의 연결을 맺어주기 위한 메소드.
      
       public static void close() throws SQLException {
             if (dbConn != null){
                   if(!dbConn .isClosed()){
                         dbConn.close();
                  }
            }
      }
       //db와의 연결을 끊어주는 메소드
}
// ex) 연결하기 예제

import java.sql.Connection;


public class jdbcTest {

       public static void main(String[] args) {

             try{
                  Connection conn = DBConn.getConnection ();
                  //정의한 DBConn 클래스로 손쉽게 연결.
                  System. out.println("오라클에 연결되었습니다." );
            } catch(Exception e){
                  System. out.println(e.toString());
            }
      }

}

문제점

  • 객체지향 프로그래밍의 핵심인 상속다형성을 해친다.

  • 객체지향 프로그래밍의 또 다른 핵심인 정보 은닉을 해친다. 공유의 목적으로 생성된 클래스이기 때문에, 객체를 요청하는 메소드를 public으로 강제할 수밖에 없다.

  • Java의 고정적 싱글턴 패턴은 객체가 하나인 것을 보장할 수 없다.

💡 싱글턴 패턴을 사용할 땐 조심하자!

즉, 싱글턴 패턴은 굉장히 많이 활용되는 패턴이나, 앞서 말한 객체지향 프로그래밍의 기본 사상들을 많이 침해하기 때문에 굉장히 비판을 많이 받는 디자인 패턴이다.

따라서 싱글턴 패턴은 사용 시 매우 조심해서 사용해야 한다.

그것이 아니라면 위의 고전적인 싱글턴 패턴이 아닌 개선된 방식으로 객체의 싱글턴 방식을 구현하여 사용해야 한다.


1-2. 팩토리 패턴 (Factory Pattern)

: 객체를 사용하는 코드에서 객체 생성 부분을 떼어내 추상화한 패턴

  • 상속 관계에 있는 두 클래스에서, 상위 클래스가 중요한 뼈대를 결정하고, 하위 클래스에서 객체 생성에 관한 구체적인 내용을 결정함

  • 상위 클래스와 하위 클래스가 분리되기 때문에 느슨한 결합을 가짐

  • 상위 클래스에서는 인스턴스 생성 방식에 대해 전혀 알 필요가 없기 때문에, 더 많은 유연성을 가지게 됨

  • 객체 생성 로직이 따로 떼어져 있기 때문에, 코드를 리팩터링하더라도 한 곳만 고칠 수 있게 됨 → 유지 보수성 증가

종류

  • 팩토리 메소드 패턴 : 객체를 생성하기 위한 인터페이스를 정의하는데, 어떤 클래스의 인스턴스를 만들지는 서브클래스에서 결정하게 만든다. 즉 팩토리 메소드 패턴을 이용하면 클래스의 인스턴스를 만드는 일을 서브클래스에게 맡기는 것.

  • 추상 팩토리 패턴 : 인터페이스를 이용하여 서로 연관된, 또는 의존하는 객체를 구상 클래스를 지정하지 않고도 생성.

구현

Java에서의 팩토리 패턴 구현

추후 작성 예정

💡 Enum 타입

  • 상수의 집합을 정의할 때 사용되는 타입
  • 코드를 리팩터링할 때 해당 집합에 관한 로직 수정 시 이 부분만 수정하면 됨 : 큰 강점



2. 구조 패턴

2-1. 프록시 패턴 (Proxy Pattern)

: 대상 객체(subject)에 접근하기 전, 그 접근에 대한 흐름을 가로채 대상 객체 앞단의 인터페이스 역할을 하는 디자인 패턴

  • 이를 통해 객체의 속성, 변환 등을 보안 / 데이터 검증 / 캐싱 / 로깅에 사용함

  • 프록시 객체로 쓰이기도 하지만, 프록시 서버로도 활용함

프록시 객체

: 어떠한 대상의 기본적인 동작(속성 접근, 할당, 순회, 열거, 함수 호출 등)의 작업을 가로챌 수 있는 객체를 뜻함

  • 자바스크립트에서 프록시 객체는 2개의 매개변수를 가짐

  • 프록시 패턴이 녹아들어 있는 객체

  • target : 프록시할 대상

  • handler : 프록시 객체의 target 동작을 가로채서 정의할 동작들이 정해져 있는 함수

프록시 서버

: 서버와 클라이언트 사이에서 클라이언트가 자신을 통해 다른 네트워크 서비스에 간접적으로 접속할 수 있게 해주는 컴퓨터 시스템이나 응용프로그램

사례

  • nginx : 비동기 이벤트 기반의 구조와 다수의 연결을 효과적으로 처리 가능한 웹 서버. nginx를 프록시 서버로 둬서 실제 포트를 숨길 수도 있고, 정적 자원을 gzip 압축하거나, 메인 서버 앞단에서의 로딩을 할 수도 있다.

    프록시 서버를 통해, 익명 사용자의 직접적인 서버로의 접근을 차단하고, 간접적으로 한 단계를 더 거침으로써 보안성을 더욱 강화할 수 있다.



3. 행동 패턴

3-1.전략 패턴 (Strategy Pattern)

: 객체의 행위를 바꾸고 싶은 경우 '직접' 수정하지 않고 전략이라고 부르는 '캡슐화한 알고리즘'을 컨텍스트 안에서 바꿔주면서 상호 교체가 가능하게 만드는 패턴. = 정책 패턴(Policy Pattern)

사례

  • 정렬을 해라! -> 각자 버블 소트, 퀵 소트 등

💡 컨텍스트
프로그래밍에서의 컨텍스트 : 상황, 맥락, 문맥을 의미하며, 개발자가 어떠한 작업을 완료하는 데 필요한 모든 관련 정보


3-2. 옵저버 패턴 (Observer Pattern)

: 주체가 어떤 객체의 상태 변화를 관찰하다가 상태 변화가 있을 때마다 메서드 등을 통해 옵저버 목록에 있는 옵저버들에게 변화를 알려주는 디자인 패턴

  • 주체 : 객체의 상태 변화를 보고 있는 관찰자
  • 옵저버 : 이 객체의 상태 변화에 따라 전달되는 메서드 등을 기반으로 '추가 변화 사항'이 생기는 객체들

사례

  • Twitter(트위터) : 주체가 포스팅을 올리게 되면 알림이 팔로워에게 감

  • Event-Driven System

  • MVC 패턴 : Model(=주체)에서 변경 사항이 생겨 update() 메서드로 View(=옵저버)에 알려주고, 이를 기반으로 Controller가 작동함

다음 포스팅은 아키텍처 패턴에 대해 마저 이야기해본다.

0개의 댓글