728x90
4. 인스턴스화를 막으려거든 private 생성자를 사용하라
정적 메서드와 정적 필드만을 담은 클래스
객체 지향을 위반하기 쉽다.
- 캡슐화를 위반한다.
- 상태를 가지지 않고, 객체의 데이터를 파라미터로 받아 처리한다.
- 데이터와 행위가 분리된다.
public class OrderProcessor {
public static void processOrder(Order order, Stock stock) {
if (stock.getRemaining() >= order.getAmount()) {
stock.subtract(order.getAmount());
}
}
}
- 상속, 다형성을 지킬 수 없다.
- static 멤버(메서드, 필드)는 상속된다고 오버라이드가 되지 않으므로 다형성을 구현할 수 없다.
static 메서드 vs 인스턴스 메서드 상속
static
메서드 : 참조 타입을 기준으로 컴파일 시점에 어떤 메서드를 호출할지 결정된다.
public class Parent {
public static void printMessage() {
System.out.println("Parent");
}
}
public class Child extends Parent {
public static void printMessage() {
System.out.println("Child");
}
}
public class Main {
public static void main(String[] args) {
Parent p = new Child();
p.printMessage(); // Parent
}
}
- 인스턴스 메서드 : 런타임에 실제 객체 타입을 기준으로 결정된다.
public class Parent {
public void instanceMethod() {
System.out.println("Parent");
}
}
public class Child extends Parent {
@Override
public void instanceMethod() {
System.out.println("Child");
}
}
Parent p = new Child();
p.instanceMethod(); // Child
사용하는 곳
- 유틸리티 클래스
public final class TimeUtils {
public static String formatTime(LocalTime time) {
}
}
- 특정 인터페이스를 구현하는 객체를 생성해주는 정적 메서드
public interface Animal { }
public class AnimalFactory {
public static Animal createDog() {
return new Dog();
}
}
- final 클래스와 관련한 메서드
- final 클래스는 상속이 불가능하므로 기능 추가를 위해 사용할 수 있다.
public final class Money {
private final int amount;
public Money(int amount) {
this.amount = amount;
}
public int getAmount() {
return amount;
}
}
public class MoneyUtils {
private MoneyUtils() {
}
public static Money add(Money money1, Money money2) {
return new Money(money1.getAmount() + money2.getAmount(), money1.getCurrency());
}
public static Money subtract(Money money1, Money money2) {
return new Money(money1.getAmount() - money2.getAmount(), money1.getCurrency());
}
}
public class Main {
public static void main(String[] args) {
Money dollars1 = new Money(100, "USD");
Money dollars2 = new Money(50, "USD");
Money sum = MoneyUtils.add(dollars1, dollars2);
}
}
private 생성자를 명시하여 인스턴스화 막기
// 코드 4-1 인스턴스를 만들 수 없는 유틸리티 클래스 (26~27쪽)
public class UtilityClass {
// 기본 생성자가 만들어지는 것을 막는다(인스턴스화 방지용).
private UtilityClass() {
throw new AssertionError();
}
}
- 생성자를 명시하지 않으면 컴파일러가 자동으로 pubilc 기본 생성자를 만든다.
- 추상 클래스로 만드는 것은 인스턴스화를 막을 수 없다. 상속받은 하위 클래스는 인스턴스화가 가능하기 때문이다.
- private 생성자를 추가하여 클래스의 인스턴스화를 막자.
private
생성자 호출시Error
를 던져 클래스 내에서 생성자를 호출하는 것을 막을 수 있다.- private 생성자를 가진 클래스는 상속이 불가능하다.
- 모든 생성자는 상위 클래스의 생성자를 호출하게 되는데, 자식 클래스가 부모 클래스의 생성자에 접근할 수 없기 때문이다.
728x90
'Java > effective java' 카테고리의 다른 글
[Effective Java] Item 6. 불필요한 객체 생성을 피하라. (0) | 2025.01.12 |
---|---|
[Effective Java] Item 5. 자원을 직접 명시하지 말고 의존 객체 주입(DI)을 사용하라. (0) | 2025.01.05 |
[Effective Java] Item 3. private 생성자나 열거 타입으로 싱글턴임을 보장하라. (0) | 2025.01.05 |
[Effective Java] Item 2. 생성자에 매개변수가 많다면 빌더를 고려하라. (0) | 2025.01.05 |
[Effective Java] Item 1. 생성자 대신 정적 팩터리 메서드를 고려하라. (0) | 2025.01.05 |