본문 바로가기
JavaScript│Node js

마틴 파울러 리팩토링 Replace Type code with Subclasses

by 자유코딩 2020. 1. 10.

종종 코드로 비슷한 것들을 만들어내야 할 때가 있습니다.

 

그럴 때 서브 클래스를 활용 할 수 있습니다.

 

이번에는 아래 코드를

function createEmployee(name, type) {
    return new Employee(name,type);
}

아래 코드로 바꿉니다

function createEmployee(name, type) {
    switch (type) {
        case "engineer": return new Engineer(name);
        case "salesman": return new Salesman(name);
        case "manager": return new Manager(name);
    }
}

위의 코드처럼 타입을 넣으면 되긴 합니다.

하지만 이렇게 서브 클래스를 사용하면 2가지 것이 가능합니다

첫번째는 조건문에서 다형성을 활용할 수 있게 됩니다 - Replace Conditional with Polymorphism

두번째는 서브 클래스로 만들어서 필드를 이동시킬 수 있습니다. - Push down fields 를 사용 할 수 있습니다.

 


수행 절차

type 코드 부분을 encapsulate 합니다.

type 코드에 대한 서브 클래스를 만듭니다.

조건문 로직을 만듭니다.

테스트

서브 클래스를 만드는 것을 반복하고 조건문에 추가합니다

type 코드를 지웁니다

테스트

push down fields 와 replace conditional with polymorphism 을 사용합니다.

 


코드를 통해서 더 살펴보겠습니다.

class Employee {
    constructor(name, type) {
        this.validateType()
        ...
    }
}


class EmployeeType {
    get capitlaizedName() {
        ....
    }
}
class Engineer extends EmployeeType {

}
class Salesman extends EmployeeType {

}
class Manager extends EmployeeType {

}

EmployeeType 클래스를 만들고

서브 클래스들을 만듭니다.

그리고 호출하는 부분에서 아래 코드처럼 사용하면 됩니다.

function createEmployee(name, type) {
    switch (type) {
        case "engineer": return new Engineer(name);
        case "salesman": return new Salesman(name);
        case "manager": return new Manager(name);
    }
}

Example. Using Indirect Inheritence

간접적인 상속과 함께 사용하기

 

첫번째 경우로 돌아가서 이번에는 파트타임과 풀타임 직원에 대한 서브 클래스를 가지고 있다고 가정한다.

이번에는 Employee 의 서브 클래스를 낼 수 없다.

그리고 이렇게 하는 또 다른 이유는 Employee의 type을 바꿀 수 있는 가능성을 남겨두기 위함이다.

class Employee {
    constructor(name, type) {...}
    validateType(arg) {
        ...
    }    
    get type() { return this._type }
    get type(arg) { this._type = arg; }

    get capitalizedType() {
        return this._type  ....
    }
    toString() {
        ....
    }
}

 

이번에는 먼저 Replace Primitive with Object 를 사용한다.

 

class EmployeeType {
    constructor(aString) {
        ...
    }
    toString() { ... }
}
class Employee {
    constructor(name, type) {...}
    validateType(arg) {
        ...
    }    
    get typeString() { return this._type }
    get type(arg) { this._type = arg; }

    get capitalizedType() {
        return this.typeString.charAt(0).toUpperCase() + this._typeString.subStr...;
    }
    toString() {
        return this._type.toString();
    }
}

 

capitalized 타입 등에서 참조해서 접근하도록 변경한다.

그리고 replace type code with subclasses 를 적용한다.

 

class Employee {
    ...
    set type(arg) { this._type = Employee.createEmployeeType(arg); }
    static createEmployeeType(aString) {
        switch (aString) {
            case "engineer": return new Engineer();
            case "manager": return new Manager();
            case "salesman": return new Salesman();
            default: throw new Error();
        }
    }
    ...
}

class EmployeeType {
}
class Engineer extends EmployeeType {

}
class Salesman extends EmployeeType {

}
class Manager extends EmployeeType {

}

비어있는 EmployeeType 이 있는데 이건 그대로 둔다.

코드 자체의 설명을 돕는다.

그리고 EmployeeType 안에 로직을 추가하면 전체 서브클래스에 추가 할 수 있는 좋은 부분도 된다.

class EmployeeType {
    get capitlaizedName() {
        ....
    }
}
class Engineer extends EmployeeType {

}
class Salesman extends EmployeeType {

}
class Manager extends EmployeeType {

}

댓글