본문 바로가기
독서에서 한걸음

타입 코드를 서브클래스로 변경하기

by oncerun 2022. 12. 19.
반응형

비슷하지만 다른 것들을 표현해야 하는 경우, 나는 열거형을 많이 사용한다. 

 

이를 통해 타입 검증을 하거나 필요한 정보를 저장하고 있다가 제공해주거나 해당 값에 대한 기능을 제공하는 메서드를 포함할 수 있기 때문이다. 

 

분기에 대한 생각 없이 Enum을 사용하다보면 매우 좋고 한계가 없어 보인다. 

 

하지만 최근 각각의 타입에 맞는 기능을 추가 구현해야하는 요청이 있는데, 이 경우 if문이나 switch문을 사용해

타입마다 해야하는 로직을 작성하는 경우가 많아졌다. 

 

이는 보기도 좋지 않고 타입이 추가될 때마다 해당 코드를 찾아서 고쳐야 하는 상황.. 즉 변경점이 퍼져있어 하나의 코드를 고쳤지만 여러 모듈에 영향을 받는 상황이 됐다. 

 

이러한 상황에 적용할 수 있는 리팩토링을 찾아보았다.

 

Replace Type Code with Subclasses

 

조건문을 다형성으로 표현할 수 있을 때, 서브클래스를 만들고 조건부 로직을 다형성으로 바꾸자.

 

특정 타입에만 유효한 필드가 있을 수 있다. 

 

이는 enum을 사용하게 되면 특정 타입만 필드가 필요한 경우가 있다. 이 경우 다른 필드는 빈 문자열을 갖거나 무의미한 값 (0, 1)과 같이 기본값을 설정해야 한다. 

 

이런 경우 서브 클래스를 만들고 필드 내리기를 사용할 수 있다.

 

 

우선 상속이 가능한 경우를 살펴보자.

 

public class Employee {

    private String name;

    private String type;

    public Employee(String name, String type) {
        this.validate(type);
        this.name = name;
        this.type = type;
    }

    private void validate(String type) {
        List<String> legalTypes = List.of("engineer", "manager", "salesman");
        if (!legalTypes.contains(type)) {
            throw new IllegalArgumentException(type);
        }
    }

    public String getType() {
        return type;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", type='" + type + '\'' +
                '}';
    }
}

여기엔 3가지 타입이 존재한다 enginner, manager, salesman 이들을 각각의 서브클래스로 만들어 보자.

 

public class Engineer extends Employee{

    public Engineer(String name, String type) {
        super(name, type);
    }

    @Override
    public String getType() {
        return "engineer";
    }
}

facotry method를 부모 클래스에 만들어 주었다.

 

//factory method
public static Employee createEmployee(String name, String type) {
    return switch (type) {
        case "engineer" -> new Engineer(name);
        case "manager" -> new Manager(name);
        case "salesman" -> new SalesMan(name);
        default -> throw new IllegalArgumentException(type);
    };
}

 

이후 기존 타입을 가져오는 것을 서브클래스에서 책임지도록 하고 코드를 변경해주었다.

 

public abstract class Employee {

    private String name;

    private String type;

    protected Employee(String name) {
        this.name = name;
    }

    //factory method
    public static Employee createEmployee(String name, String type) {
        return switch (type) {
            case "engineer" -> new Engineer(name);
            case "manager" -> new Manager(name);
            case "salesman" -> new SalesMan(name);
            default -> throw new IllegalArgumentException(type);
        };
    }
    protected abstract String getType();

    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", type='" + getType() + '\'' +
                '}';
    }
}

 

만약 이미 상속구조를 가지고 있다면 어떻게 할 것인가?

 

기본 타입을 감싸는 클래스를 만들고

public class EmployeeType {
}

 

해당 클래스를 각각의 타입이 상속받도록 한다.

 

public class Manager extends EmployeeType{}

public class Salesman extends EmployeeType{}

public class Engineer extends EmployeeType{}
public class Employee {

    private String name;

    private EmployeeType type;

    public Employee(String name, String type) {
        this.name = name;
        this.type = this.employeeType(type);
    }
    public EmployeeType employeeType(String type) {
        return switch (type) {
            case "engineer" -> new Engineer();
            case "manager" -> new Manager();
            case "salesman" -> new Salesman();
            default -> throw new IllegalArgumentException(type);
        };
    }

    public String capitalizedType() {
        return this.type.capitalizedType();
    }

    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", type='" + type.toString() + '\'' +
                '}';
    }
}

 

간접적으로 상속을 활용한 타입을 서브 클래스로 만들 수 있다. 

반응형

'독서에서 한걸음' 카테고리의 다른 글

Repeated Switches  (0) 2022.12.22
Replace Conditional with Polymorphism  (0) 2022.12.21
Primitive Obsession  (0) 2022.12.19
Shotgun Surgery  (0) 2022.12.18
Divergent Change  (0) 2022.12.14

댓글