[TIL - 0912] 디자인패턴(싱글턴), Cloud 서비스 알아보기

디자인패턴

  • 평소 전략 패턴을 사용해서 객체 간의 디펜던시를 끊고 개발을 많이 하면서 디자인패턴의 효용성에 대해서 알게 되었음
  • 이전에는 이런 것까지 알아야해? 했지만 지금은 알고 있으면 문제 상황에서 해결할 수 있는 방법 하나쯤을 더 알고 있는 것이 아닐까 라는 생각이 듦 그래서 하루 하나씩 디자인패턴에 대해서 알아보고자 함 : 다 외우겠다는 것은 아니지만 이해는 하고 있자는 취지!

디자인 패턴 종류

  1. 전략 패턴
  2. 싱글턴 패턴
  3. 스테이트 패턴
  4. 템플릿 메소드 패턴
  5. 옵저버 패턴
  6. 커맨드 패턴
  7. 데커레이터 패턴
  8. 팩토리 메소드 패턴
  9. 추상 팩토리 패턴
  10. 컴포지트 패턴

싱글턴 패턴

  • 인스턴스 개수를 여러개가 아닌 1개로 유지하는 패턴 : 공통적으로 사용해도 되는 상황에서 사용(도메인 분석할 때 하나만 존재해야하는 객체는 싱글턴 패턴으로 추상화)
  • 주의할 점 : 멀티쓰레드 환경에서 동시에 싱글턴 인스턴스를 사용한다고 가정했을 때 싱글턴 인스턴스가 상태 변수를 가지게 된다면 부작용에 대해서도 생각해야함(그래서 상태값을 가지지 않도록 하는 것이 최선)
    • 상태변수 : 변경될 수 있는 값을 말함, 동시적으로 접근하여 상태값 변경을 한다고 했을 때 예상치 못한 결과가 나올 수 있음
    • 상태값을 가지더라도 동시 접근 상황에 대한 처리(잠금)를 잘하던지, 아예 static 메소드와 상수를 가진 정적 클래스로 만드는 2가지 해결책이 있지 않을까 라는 생각이 듦
    • lazy init을 할 때도 마찬가지로 생성할 때 동시에 접근해서 두 개의 인스턴스를 만들어 버린다면? vs 싱글턴 패턴을 적용할 인스턴스를 미리 모두 생성해놓는다면 메모리 비효율을 초래할 수 있음(lazy holder 사용하기 - 클래스로더는 런타임에 필요한 시기에 클래스 정보를 메모리에 로드함)
    • 리플렉션 API를 사용해서 private 생성자 메소드를 호출할 수 있다는 점을 알고 있어야함 : 물론 그렇게 사용할 리는 없겠지만(예외 처리를 해놓음이 안전하지않을까? - 직접적으로 접근하려고 하는 경우)
public class Print { 
    private static Print print = new Print();

    private Print() {
    }

    public static Print of() {
        return print;
    }
}


/* 리플렉션 private 인스턴스 접근 */
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
    Constructor constructor = Printer.class.getDeclaredConstructor();
    constructor.setAccessible(true);
    Printer printer = (Printer) constructor.newInstance();
    printer.print();
}


/* lazy holder 방식 - 인스턴스가 진짜 필요한 시점에 생성(동시 문제도 메모리 비효율도 같이 잡음)  */
public class Printer {

    private Printer() {
    }

    private static class LazyPrinter {
        private static final Printer PRINTER = new Printer();
    }

    public static Printer of() {
        return LazyPrinter.PRINTER;
    }
}
  • 생각드는 부분 : 정적 클래스말고 싱글턴 인스턴스를 사용하는 것은 extends, implements를 사용해서 관계를 뚜렷하게 나타냄과 구현에 있어서 강제를 할 수 있기 때문이 아닐까 라는 생각이 듦
    • 다형성을 이용한 구현을 할 수 있기 때문이라는 생각이 추가적으로 : static 메소드를 호출하는 것과 인스턴스를 받을 수 있게 인자 타입으로 나타낼 수 있는 것과의 차이랄까
public interface Printable {
    
}

public void print(Printable printable)
  • 새롭게 알게된 부분 : volatile 키워드 사용 : 조금 더 알아보기(CPU 캐시와 메인 메모리, volatile)
    • CPU 데이터 캐시 처리에 대해서 알게됨 : 메인 메모리에서 읽은 값을 캐시 해두고 캐시한 값에 대해 write/read를 한다는 것, 특정 시점에 메인 메모리에 쓰기한다는 것 - 성능
    • 멀티쓰레드 환경에서 공유 객체의 상태 변수의 값이 변경되었을 때 즉각 메인 메모리에 write해서 다른 쓰레드에서 캐시해둔 데이터를 read 하지않고 바로바로 메인 메모리에서 값을 읽도록하여 안전한 프로그래밍이 가능하도록 하는 키워드
    • 캐시한 값을 read 하는 것보다 성능 상에서는 단점이 있으므로 꼭 필요한 값에만 사용하도록
    • 멀티쓰레드 환경 처리(thread-safe하게)에 대해 관심을 더 가져야겠다

참고자료

Cloud 서비스로 시스템 구성하기를 맛보기에 앞서 서비스 살펴보기 - AWS

  • 클라우드 서비스를 통해서 서비스를 제공하는 것이 보편화 되고 있는데, 정작 써본 서비스 라고는 EC2, RDS, S3가 전부(그마저도 EC2 이외에는 자주 써보지도 않음…)라서 어떤 서비스인지라도 알기위해 하나씩 살펴보는 시간을 가질 생각

알아볼 AWS 주요 서비스

  • EC2
  • Elastic Beanstalk
  • Cloud Watch(Auto Scailing)
  • RDS
  • DynamoDB
  • Elastic Cache
  • Elastic Search
  • Lambda
  • Simple Queue Service
  • IAM
  • Key Management Service

참고할 자료