티스토리 뷰

목차



    반응형

     

     

     

     

     

    Java 설계 패턴의 구조적 원리를 감각적으로 시각화한 일러스트

     

     자바(Java) 언어는 객체지향 프로그래밍의 대표적인 언어로, 유지보수성과 확장성을 중요시하는 소프트웨어 개발에 널리 사용됩니다. 그 중심에는 디자인패턴이 존재하며, 이는 소프트웨어 설계 시 반복적으로 마주치는 문제들을 효율적으로 해결하기 위한 일종의 설계 템플릿입니다.

     

     그중에서도 싱글톤(Singleton) 패턴과 팩토리(Factory) 패턴은 객체 생성과 관련된 문제를 해결하기 위해 매우 자주 사용됩니다.

     이 패턴들은 클래스의 생성자를 private으로 선언함으로써 외부에서의 객체 생성을 제한하고, 내부 로직을 통해 인스턴스를 제어하는 방식으로 작동합니다.

     

     이번 글에서는 이 두 패턴의 작동 원리, 구조, 그리고 생성자 접근 제한자 설정의 중요성에 대해 심도 있게 살펴보겠습니다.

     

     

    싱글톤 패턴 이해하기

     싱글톤(Singleton) 패턴은 소프트웨어 설계에서 단 하나의 객체만 존재하도록 보장하는 디자인 패턴입니다. 자바에서는 프로그램 전반에 걸쳐 공유되어야 할 설정값, 로그 기록기(logger), 데이터베이스 연결 객체 등에서 자주 사용됩니다.

     

     싱글톤의 핵심은 인스턴스의 유일성 보장전역 접근입니다. 이를 구현하기 위해 클래스의 생성자를 private으로 선언하여 외부에서 인스턴스를 직접 생성하는 것을 원천적으로 차단합니다. 대신, 클래스 내부에서 static으로 선언된 단 하나의 인스턴스를 보관하고, 이를 반환하는 static 메서드(getInstance)를 제공합니다.

    public class Singleton {
        private static Singleton instance = new Singleton();
    
        private Singleton() {
            // 외부에서 인스턴스 생성 금지
        }
    
        public static Singleton getInstance() {
            return instance;
        }
    }
    

     

     이 구현은 클래스 로딩 시점에 인스턴스가 생성되는 이른 초기화 방식으로, 멀티스레드 환경에서도 안전합니다. 그러나 인스턴스 생성에 자원이 많이 들거나, 실제로 사용되지 않을 가능성이 있을 경우에는 ‘지연 초기화(lazy initialization)’를 사용하는 방식도 고려됩니다. 이 경우 null 체크와 동기화(synchronized)를 통해 멀티스레드에서의 안전성을 확보해야 합니다.

     

     싱글톤은 단순해 보이지만, 잘못 구현되면 시스템 전반에 심각한 영향을 줄 수 있으므로 주의가 필요합니다. 특히 테스트 환경에서는 전역 인스턴스가 문제를 유발할 수 있어 테스트 친화적인 설계가 필요합니다.

    팩토리 패턴과 객체 생성 관리

     팩토리(Factory) 패턴은 객체의 생성 과정을 외부에 노출시키지 않고, 생성 로직을 별도의 클래스나 메서드에 위임함으로써 객체 생성을 보다 유연하게 관리할 수 있도록 돕는 패턴입니다.

     

     특히 다양한 유형의 객체를 상황에 따라 다르게 생성해야 하는 경우, 팩토리 패턴은 코드의 복잡도를 줄이고 결합도를 낮춰주는 효과적인 방법입니다. 팩토리 패턴은 주로 인터페이스나 추상 클래스를 활용하여, 런타임 시점에서 적절한 구현 객체를 반환하는 구조로 설계됩니다.

    public class Product {
        private Product() {
            // 외부에서 생성 금지
        }
    
        public static Product create() {
            return new Product();
        }
    }
    

     

     위 구조에서 핵심은 생성자를 private으로 선언하여 외부에서 직접 new Product()를 할 수 없도록 하고, 대신 정적 메서드인 create()를 통해 객체를 생성하도록 유도하는 것입니다.

     

     이를 통해 객체 생성 전 로직 추가(예: 유효성 검사, 설정 초기화 등)가 가능해지고, 필요시 동일 객체를 반환하거나 풀링(pooling) 기법을 적용해 리소스를 절약할 수 있습니다.

     

     더 고급 패턴인 팩토리 메서드는 인터페이스와 서브 클래스들을 활용하여 확장성과 유지보수성을 강화합니다. 예를 들어 Shape이라는 인터페이스와 이를 구현하는 Circle, Rectangle 클래스가 있다면, 팩토리 클래스에서 조건에 따라 다른 객체를 반환할 수 있습니다.

     

     팩토리 패턴은 객체 생성 책임을 분리함으로써, SOLID 원칙 중 단일 책임 원칙(SRP)과 개방-폐쇄 원칙(OCP)을 효과적으로 구현할 수 있도록 도와줍니다.

     

     

    생성자를 private으로 선언하는 이유

     생성자를 private으로 선언하는 것은 객체지향 설계에서 매우 강력한 캡슐화 도구입니다. 일반적으로 클래스는 public 생성자를 제공하여 객체를 자유롭게 생성할 수 있도록 하지만, 경우에 따라 외부에서 객체 생성을 제어해야 할 필요가 있습니다. 이때 사용하는 것이 바로 private 생성자입니다.

     

     주로 싱글톤이나 팩토리 패턴과 같은 디자인패턴에서, 객체 생성을 한정하거나 특정 방식으로만 허용하고 싶을 때 사용됩니다.

     

     private 생성자의 장점은 다음과 같습니다.

    • 객체 생성을 제한
      • 외부에서는 new 키워드로 객체를 만들 수 없기 때문에, 객체 생성 경로를 명확히 통제할 수 있습니다.
    • 정적 메서드를 통한 제어
      • static 메서드를 통해 객체를 생성하거나 반환함으로써 생성 전후에 로직을 삽입하거나, 동일 객체를 재사용하는 등의 컨트롤이 가능합니다.
    • 테스트와 확장에 유리
      • 테스트 시 객체 생성을 mocking 하거나 상황에 맞게 대체할 수 있어 단위 테스트가 용이해집니다.
    • 불변성 유지
      • 싱글톤처럼 상태가 변하지 않는 객체를 구현할 때 객체 생성을 막음으로써 설계의 일관성을 지킬 수 있습니다.

     물론 private 생성자를 무분별하게 사용할 경우 확장성이 떨어지고, 상속이 불가능해질 수 있습니다. 이러한 구조는 신중하게 설계되어야 하며, 생성자 외에 팩토리 메서드나 빌더 패턴을 함께 사용하는 방식으로 유연성을 확보할 수 있습니다.

     

     결론적으로 생성자를 private으로 선언하는 것은 객체 생성의 책임과 통제권을 설계자에게 부여하는 고급 설계 기법이며, 이를 통해 보다 안정적이고 예측 가능한 시스템을 구성할 수 있습니다.

     

     자바 디자인패턴에서 싱글톤과 팩토리 패턴은 객체 생성이라는 주제를 중심으로 깊은 연관성을 가지며, 둘 모두 생성자 접근제한자 설정을 통해 객체의 생명주기를 정밀하게 제어합니다.

     

     특히 생성자를 private으로 선언함으로써 외부로부터의 무분별한 객체 생성을 막고, 내부 로직을 통해 객체 생성을 안전하게 유도할 수 있습니다. 이러한 패턴들은 자바 개발자로서 필수적으로 익혀야 할 핵심 개념이며, 실제 프로젝트에서의 적용을 통해 진정한 가치를 체감할 수 있습니다.

     

     객체지향 설계를 한 단계 끌어올리고 싶다면, 오늘 배운 내용을 코드에 직접 적용해 보시기 바랍니다.

     

     

    반응형