티스토리 뷰

목차



    반응형

    Java 클래스 내부에서만 허용된 객체 생성 구조를 시각적으로 형상화한 일러스트

     

     

     자바(Java)에서 클래스의 생성자를 private으로 선언하는 것은 흔한 일이 아니지만, 특정한 상황에서는 반드시 필요한 설계 전략이 됩니다. 특히 디자인패턴 중 싱글톤(Singleton), 팩토리(Factory) 또는 빌더(Builder) 패턴 등에서 객체 생성을 제어하거나 제한하고자 할 때 많이 사용됩니다.

     

     이 글에서는 생성자의 접근제한자 중 private을 선택하는 이유에 대해 다양한 시각에서 비교하고, 패턴별로 어떻게 적용되는지를 구체적인 예제와 함께 분석해 보겠습니다.

    public 생성자와 private 생성자의 차이점

     자바에서 생성자는 클래스의 인스턴스를 만들기 위한 특별한 메서드입니다. 일반적으로는 public 생성자를 사용하여 외부 클래스가 자유롭게 객체를 생성할 수 있도록 합니다. 반면 private 생성자는 외부에서 객체를 생성하지 못하게 제한하며, 클래스 내부에서만 객체 생성을 허용합니다.

     

     이 차이는 매우 단순해 보일 수 있지만, 실제 소프트웨어 설계에서는 큰 의미를 가집니다.

     public 생성자의 가장 큰 장점은 사용 편의성과 확장성입니다. 객체를 어디서든 생성할 수 있고, 다양한 방식으로 활용할 수 있습니다.

    Person person = new Person("홍길동");

     

     하지만 이런 방식은 객체 생성의 책임이 분산되고, 예기치 않은 객체 생성을 방지할 수 없다는 단점도 존재합니다. 반면 private 생성자는 이러한 문제를 해결할 수 있는 강력한 도구입니다. 객체 생성을 하나의 경로로만 제한할 수 있기 때문에, 유지보수와 테스트에 유리합니다.

    싱글톤/팩토리/빌더 패턴에서의 적용 예

     private 생성자의 실제 활용은 다양한 디자인패턴에서 두드러집니다. 가장 대표적인 예는 싱글톤 패턴(Singleton Pattern)입니다. 싱글톤은 애플리케이션에서 단 하나의 인스턴스만 생성되어야 하는 경우에 사용되며, 그 구현을 위해 생성자를 private으로 숨기고, 클래스 내부에 static 인스턴스를 보관하는 방식으로 구성됩니다.

    public class Singleton {
        private static final Singleton instance = new Singleton();
    
        private Singleton() {}
    
        public static Singleton getInstance() {
            return instance;
        }
    }

     

     또한 팩토리 패턴(Factory Pattern)에서도 객체 생성을 외부로부터 통제하기 위해 생성자를 private으로 설정합니다.

    public class Car {
        private Car() {}
    
        public static Car create(String type) {
            return new Car();
        }
    }

     

     마지막으로 빌더 패턴(Builder Pattern)에서도 private 생성자가 활용됩니다.

    public class User {
        private String name;
        private int age;
    
        private User(Builder builder) {
            this.name = builder.name;
            this.age = builder.age;
        }
    
        public static class Builder {
            private String name;
            private int age;
    
            public Builder name(String name) { this.name = name; return this; }
            public Builder age(int age) { this.age = age; return this; }
    
            public User build() {
                return new User(this);
            }
        }
    }

    유지보수성과 테스트에서의 장단점

     private 생성자를 통해 객체 생성을 제한하면, 전체 시스템의 예측 가능성안정성이 높아집니다. 생성자가 노출되어 있지 않기 때문에 객체 생성 경로가 명확하고, 유지보수 시 문제를 추적하기가 쉬워집니다.

     

     테스트에서는 필요한 객체를 특정 방식으로만 생성할 수 있어 테스트 환경을 쉽게 통제할 수 있으며, 모의 객체로 교체하거나 생성 로직을 분리해 테스트 유연성도 확보할 수 있습니다.

     

     하지만 단점도 존재합니다. 대표적인 예로 상속이 불가능하며, 리플렉션 등을 이용한 우회 접근이 가능하다는 점은 보안상 위험을 초래할 수 있습니다. 따라서 private 생성자 사용은 매우 강력하지만, 신중하게 설계해야 합니다.

     

     결론적으로 생성자 접근제어자는 단순한 문법 요소가 아니라, 시스템 아키텍처 전체에 영향을 미치는 중요한 설계 도구입니다.

     생성자를 private으로 선언하는 이유는 단순히 객체 생성을 숨기기 위한 것이 아닙니다. 그것은 설계자가 객체의 생성 시점, 생성 방식, 생성 조건 등을 정확히 제어할 수 있는 구조를 만들기 위한 고급 설계 전략입니다.

     

     싱글톤, 팩토리, 빌더 등 다양한 디자인패턴에서 활용되며, 유지보수성과 테스트 효율성까지 고려한 시스템 설계의 핵심이 됩니다.

     자바 개발자로서 객체 생성을 단순한 작업이 아닌 설계의 일부로 바라본다면, 생성자의 접근제한자 설정은 무시할 수 없는 중요한 선택이 될 것입니다.

     

     

    반응형